├── LICENSE
├── README.md
├── smshash.py
└── xxd_w.exe
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Funambol
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # android-sms-hash-generator
2 | Small and effective python script to compute the android app's hash to properly configure the SMS Signup with autoverification code.
3 |
4 | # Download
5 | Download the latest version from [Releases](https://github.com/funambol/android-sms-hash-generator/releases) page.
6 |
7 | # Requirements
8 | - JDK
9 | - Python3
10 |
11 | # Usage
12 | smshash.py needs four parameters:
13 | - keystore: the absolute or relative path of your Android keystore
14 | - alias: the alias of the keystore
15 | - keypass: the passphrase of the keystore
16 | - appid: your app's package name
17 |
18 | Example:
19 | ```python
20 | python3 smshash.py path/keystore MyAndroidKey xxxxxxxxxxxx com.example.myapp
21 | ```
22 |
23 | For help:
24 | ```python
25 | python3 smshash.py -h
26 | ```
27 |
28 | >**Please note:**
29 | >On Windows, smshash.py and xxd_w.exe must be placed in the same folder.
30 | >
xxd_w.exe is not used on other platforms.
31 |
32 | # Why
33 | Google Play services uses the hash string to determine which verification messages to send to your Android app. The hash string is made of your app's package name and your app's public key certificate.
34 | According to Google [documentation](https://developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string) it can be generated with this command:
35 | ```bash
36 | keytool -exportcert -alias MyAndroidKey -keystore MyProductionKeys.keystore | xxd -p | tr -d "[:space:]" | echo -n com.example.myapp `cat` | sha256sum | tr -d "[:space:]-" | xxd -r -p | base64 | cut -c1-11
37 | ```
38 | But that command has some issues:
39 | - It's not multi platform: it works fine on Linux, it could work on Mac with a small change, it does not work at all on Windows.
40 | - It does not emit an error if the keytool command fails and it generates the hash of the error message instead.
41 |
42 | This python script does not have those issues, it is multi platform and if the keytool command fails (for instance because the keystore passphrase is wrong), the script stops and emit an error message.
--------------------------------------------------------------------------------
/smshash.py:
--------------------------------------------------------------------------------
1 | import platform
2 | import os
3 | import sys
4 | import argparse
5 | import subprocess
6 | from subprocess import Popen, PIPE
7 | import base64
8 | from shutil import which
9 | try:
10 | import hashlib
11 | except ImportError:
12 | sys.exit("please install 'hashlib' module: pip install hashlib")
13 |
14 | #the parser
15 | cmd_parser = argparse.ArgumentParser(description="Computing app's hash string for Android SMS handling")
16 | cmd_parser.add_argument('keystore', type=str, help='Keystore file')
17 | cmd_parser.add_argument('alias', type=str, help='Keystore alias')
18 | cmd_parser.add_argument('keypass', type=str, help='Key password')
19 | cmd_parser.add_argument('appid', type=str, help='Package name of the Android app')
20 | args = cmd_parser.parse_args()
21 |
22 | __encoding_name__ = "iso-8859-1" # Latin 1
23 |
24 | def isWindows():
25 | return platform.system() == "Windows"
26 |
27 | def cmdExist(program):
28 | return which(program) is not None
29 |
30 | def exitWithError(error):
31 | print(error, file=sys.stderr)
32 | sys.exit(1)
33 |
34 | def call(cmd):
35 | cmd = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=PIPE, stderr=PIPE, encoding=__encoding_name__)
36 | cmdResult = cmd.communicate()
37 | return (cmd.returncode, cmdResult[0], cmdResult[1])
38 |
39 | def getKeytoolCommand(withxxd = False):
40 | keytoolName = "keytool"
41 | if not cmdExist(keytoolName):
42 | exitWithError("Error: keytool command not found. Be sure the JDK is installed and available in the PATH")
43 |
44 | if withxxd:
45 | return keytoolName + " " + "-alias " + args.alias + " -exportcert -keystore " + args.keystore + " -storepass " + args.keypass + " | " + getxxdName() + " -p"
46 | else:
47 | return keytoolName + " " + "-alias " + args.alias + " -exportcert -keystore " + args.keystore + " -storepass " + args.keypass
48 |
49 | def getxxdName():
50 | xxdName = "xxd"
51 | if isWindows():
52 | xxdName = "xxd_w"
53 | if not cmdExist(xxdName):
54 | exitWithError("Error: " + xxdName + " not found. If you are on Windows, the program xxd_w.exe must be placed in the current folder")
55 | return xxdName
56 |
57 | def getSignature():
58 | keytoolCommand = getKeytoolCommand()
59 | returncode, out, err = call(keytoolCommand)
60 | if returncode != 0:
61 | print(out)
62 | print(err)
63 | exitWithError("keytool command failed. Please check the alias and the password are correct")
64 | return out
65 |
66 | def getHexSignature():
67 | keytoolWithxxd = getKeytoolCommand(True)
68 | returncode, out, err = call(keytoolWithxxd)
69 | if returncode != 0:
70 | print(out)
71 | print(err)
72 | exitWithError("keytool | xxd command failed")
73 | return out
74 |
75 | def removeWhitespaces(value):
76 | return "".join(value.split())
77 |
78 | def appendApplicationId(value):
79 | return args.appid + " " + value
80 |
81 | def computeSha256(value):
82 | m = hashlib.sha256()
83 | m.update(value.encode(__encoding_name__))
84 | return m.digest()
85 |
86 | def formatSignature(signature):
87 | signatureNoSpaces = removeWhitespaces(signature)
88 | return appendApplicationId(signatureNoSpaces)
89 |
90 | # Call getSignature() to check if the alias and password provided are correct: if not correct the program exits with error
91 | signature = getSignature()
92 | hexSignature = getHexSignature()
93 |
94 | formattedSignature = formatSignature(hexSignature)
95 | sha256 = computeSha256(formattedSignature)
96 | base64 = base64.b64encode(sha256)
97 |
98 | # The hash to use for the SMS is the first 11 chars
99 | print(base64.decode(__encoding_name__)[0:11])
100 |
--------------------------------------------------------------------------------
/xxd_w.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/funambol/android-sms-hash-generator/9b88cdd570ea4a041aa6e4b2aa6134c4c3b6b5b4/xxd_w.exe
--------------------------------------------------------------------------------