-
Notifications
You must be signed in to change notification settings - Fork 362
/
Copy pathtermux-keystore.in
314 lines (293 loc) · 13.3 KB
/
termux-keystore.in
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
#!@TERMUX_PREFIX@/bin/sh
set -e -u
readonly CMD_BASE="@TERMUX_PREFIX@/libexec/termux-api Keystore"
SCRIPTNAME=termux-keystore
show_usage () {
echo "Usage: $SCRIPTNAME command"
echo "These commands are supported:"
echo " list [-sd]"
echo " delete <alias> [-s pref]"
echo " generate [alias] [-bcilq] [-a alg] [-s size] [-p purposes] [-u validity]"
echo " sign <alias> <algorithm>"
echo " verify <alias> <algorithm> <signature>"
echo " encrypt <alias> [-a alg] [-q] [-p path] [-s pref] [-t timeout]"
echo " decrypt <alias> [-a alg] [-q] [-p path] [-s pref] [-t timeout]"
echo
echo "list: List either the keys stored inside the keystore or data in shared preferences."
echo " -s Shared preferences. Shows shared preferences. [Omit to show keys]"
echo " -d Detailed results. For keys, shows key parameters."
echo " For shared preferences, shows data of preferences."
echo
echo "delete: Delete either a given key from the keystore or a given shared preference."
echo " alias Alias of the key or shared preference-associated key to delete."
echo " -s pref Shared preference to delete. [Omit to delete key"
echo " and all shared preferences]"
echo
echo "generate: Create a new key inside the hardware keystore."
echo " alias Alias of the key. If not supplied then randomly generated."
echo " For generation, ensure /dev/urandom is accessible."
echo " -b Biometric flag, require e.g. fingerprint, iris, or face."
echo " -c Credentials flag, require e.g. PIN, pattern, or password. (≥Android11)"
echo " -i Invalidate flag, key invalidated by new biometric enrollments. (≥Android7)"
echo " (iff -u validity=-1)"
echo " -l Locked flag, allows key access while device is locked. (≥Android9)"
echo " -q Quiet flag, silences key specifications output."
echo " -a alg Algorithm. Asymmetric key pairs are 'RSA' or 'EC'."
echo " Symmetric key ciphers or cipher options specified as"
echo " 'ALG/MODE/PADDING'. ALG is 'RSA' or 'AES'."
echo " See: Android keystore#SupportedAlgorithms"
echo " [Asymmetric Default: 'RSA']"
echo " [Symmetric Default: 'AES/GCM/NoPadding']"
echo " -s size Key size. For RSA, the options are 2048, 3072, and 4096."
echo " For EC, the options are 256, 384, and 521."
echo " For AES, the options are 128, 192, and 256."
echo " [Defaults to smallest size]"
echo " -p purposes Key purposes. See: Android KeyProperties.PURPOSE flags"
echo " [Asymmetric Default is sign+verify: '4|8']"
echo " [Symmetric Default is encrypt+decrypt: '1|2']"
echo " -u validity User validity duration in seconds. Specifies duration the key can be"
echo " used for after authorization if -c or -b were supplied. Default"
echo " requires authorization for every key invocation. [Default: -1]"
echo
echo "sign: Sign using the given key, the data is read from stdin and the"
echo "signature is output to stdout."
echo " alias Alias of the key to use for signing."
echo " algorithm Algorithm to use, e.g. 'SHA256withRSA'. This should"
echo " match the algorithm of the key."
echo
echo "verify: Verify a signature. The data (original file) is read from stdin."
echo " alias Alias of the key to use for verify."
echo " algorithm Algorithm that was used to sign this data."
echo " signature Signature file to use in verification."
echo
echo "encrypt: Encrypt using the given key, the data is read from a file or stdin"
echo "(in that precedence) and the encrypted data is output to stdout and/or"
echo "shared preferences with a user-supplied name. Output is of the form"
echo "[IV.length][IV][Encrypted Data] (IV omitted if IV.length is 0)."
echo " alias Alias of the key to use for encrypting."
echo " -a alg Algorithm to use in the form 'ALG/MODE/PADDING'. This should match the"
echo " algorithm of the key. If unspecified, uses key's first instance."
echo " -q Quiet flag, silences encrypted data output."
echo " -p path Path of input file. Name of filepath containing data to be encrypted."
echo " -s pref Shared preference. Name of shared preference to store encrypted data."
echo " -t timeout Timeout for authentication in seconds. Specifies the valid timeframe for"
echo " authentication. Some devices continue showing the prompt or"
echo " automatically cancel. Default is system-dependent. [Default: -1]"
echo
echo "decrypt: Decrypt using the given key, the data is read from a file, shared preference, or"
echo "stdin (in that precedence) and the decrypted data can be output to stdout. Input is"
echo "expected in the form [IV.length][IV][Encrypted Data] (IV omitted if IV.length is 0)."
echo " alias Alias of the key to use for decrypting."
echo " -a alg Algorithm to use in the form 'ALG/MODE/PADDING'. This should match the"
echo " algorithm of the key. If unspecified, uses key's first instance."
echo " -q Quiet flag, silences decrypted data output."
echo " -p path Path of input file. Name of filepath containing data to be decrypted."
echo " -s pref Shared preference. Name of shared preference containing data to be"
echo " decrypted."
echo " -t timeout Timeout for authentication in seconds. Specifies the valid timeframe for"
echo " authentication. Some devices continue showing the prompt or"
echo " automatically cancel. Default is system-dependent. [Default: -1]"
}
check_args () {
if [ "$2" != "$3" ]; then
echo "$SCRIPTNAME: $1 needs exactly $2 arguments"
exit 1
fi
}
list_Data () {
DETAILED=0; PREF=0;
while getopts ds NAME; do
case "$NAME" in
d) DETAILED=1 ;;
s) PREF=1 ;;
?) ;;
esac
done
$CMD_BASE -e command list --ei detailed "$DETAILED" --ei pref "$PREF"
}
delete_data () {
if [ $# -lt 1 ]; then
echo "$SCRIPTNAME delete: alias required"
exit 1
fi
ALIAS=$1; shift
PREF=-1;
while getopts s: NAME; do
case "$NAME" in
s) PREF=$OPTARG ;;
?) ;;
esac
done
shift $((OPTIND-1))
if [ "$#" -gt 0 ]; then echo "Unmatched argument \"$1\" ignoring: \"$*\""; fi
$CMD_BASE -e command delete -e alias "$ALIAS" -e pref "$PREF"
}
sign_data () {
check_args sign 2 $#
$CMD_BASE -e command sign -e alias "$1" -e algorithm "$2" | base64 -d
}
verify_data () {
check_args verify 3 $#
$CMD_BASE -e command verify -e alias "$1" -e algorithm "$2" \
-e signature "$(realpath "$3")"
}
encrypt_data () {
if [ $# -lt 1 ]; then
echo "$SCRIPTNAME encrypt: alias required"
exit 1
fi
ALIAS=$1; shift 1
ALGORITHM=-1; INFILE=-1; STORE=-1; TIMEOUT=-1; QUIET=0;
while getopts a:p:s:t:q NAME; do
case "$NAME" in
a) ALGORITHM=$OPTARG ;;
p) INFILE=$(realpath "$OPTARG") ;;
s) STORE=$OPTARG ;;
t) TIMEOUT=$OPTARG ;;
q) QUIET=1 ;;
?) ;;
esac
done
shift $((OPTIND-1))
if [ "$#" -gt 0 ]; then echo "Unmatched argument \"$1\" ignoring: \"$*\""; fi
$CMD_BASE -e command encrypt -e alias "$ALIAS" -e algorithm "$ALGORITHM" \
-e filepath "$INFILE" -e store "$STORE" --ei quiet "$QUIET" \
--ei authenticationTimeout "$TIMEOUT" | base64 -d
}
decrypt_data () {
if [ $# -lt 1 ]; then
echo "$SCRIPTNAME decrypt: alias required"
exit 1
fi
ALIAS=$1; shift 1
ALGORITHM=-1; INFILE=-1; STORE=-1; TIMEOUT=-1; QUIET=0;
while getopts a:p:s:t:q NAME; do
case "$NAME" in
a) ALGORITHM=$OPTARG ;;
p) INFILE=$(realpath "$OPTARG") ;;
s) STORE=$OPTARG ;;
t) TIMEOUT=$OPTARG ;;
q) QUIET=1 ;;
?) ;;
esac
done
shift $((OPTIND-1))
if [ "$#" -gt 0 ]; then echo "Unmatched argument \"$1\" ignoring: \"$*\""; fi
$CMD_BASE -e command decrypt -e alias "$ALIAS" -e algorithm "$ALGORITHM" \
-e filepath "$INFILE" -e store "$STORE" --ei quiet "$QUIET" \
--ei authenticationTimeout "$TIMEOUT" | base64 -d
}
generate_key () {
#If noargs or args starts with flags
if [ "$#" -eq 0 ] || [ -n "${1%%[!-]*}" ]; then
ALIAS="$(head -c 5 /dev/urandom | base32)"
echo "Generated Alias: \"${ALIAS?"unable to generate, please provide as argument"}\""
else
ALIAS=$1
shift
fi
# Defaults
_ALGORITHM="RSA"; MODE=-1; PADDING=-1; SIZE=-1; PURPOSES=-1
UNLOCKED=1; VALIDITY=-1; INVALIDATE=0; AUTH=0;
# Args handler
while getopts a:s:p:u:qlicb NAME; do
case "$NAME" in
q) QUIET=1 ;;
l) UNLOCKED=0 ;;
i) INVALIDATE=1 ;;
c) AUTH=$((AUTH|1)) ;;
b) AUTH=$((AUTH|2)) ;;
a) _ALGORITHM=$OPTARG ;;
s) SIZE=$OPTARG ;;
p) PURPOSES=$OPTARG ;;
u) VALIDITY=$OPTARG ;;
?) ;;
esac
done
shift $((OPTIND-1))
if [ "$#" -gt 0 ]; then echo "Unmatched argument \"$1\" ignoring: \"$*\""; fi
ALGORITHM=${_ALGORITHM%%/*}
# Begin splice by /
case "$ALGORITHM" in
"$_ALGORITHM") ;;
*) MODE=${_ALGORITHM#*/}
MODE=${MODE%/*}
if [ "$ALGORITHM" = "${_ALGORITHM%/*/*}" ]; then PADDING=${_ALGORITHM##*/}; fi ;;
esac
# End splice by /
case "$ALGORITHM" in
"RSA") case "$SIZE" in
-1) SIZE=2048 ;;
2048|3072|4096) ;;
*) echo "$SCRIPTNAME: invalid RSA key size $SIZE"; exit 1 ;;
esac
case "$MODE" in
-1) ;;
"ECB") case "$PADDING" in
-1) PADDING="OAEPPadding" ;;
"NoPadding"|"PKCS1Padding"|"OAEPPadding") ;;
*) echo "$SCRIPTNAME: invalid padding RSA/$MODE/$PADDING"; exit 1 ;;
esac ;;
*) echo "$SCRIPTNAME: invalid RSA mode $MODE"; exit 1 ;;
esac ;;
"EC") case "$SIZE" in
-1) SIZE=256 ;;
256|384|521) ;;
*) echo "$SCRIPTNAME: invalid EC key size $SIZE"; exit 1 ;;
esac
MODE=-1
PADDING=-1 ;;
"AES") case "$SIZE" in
-1) SIZE=128 ;;
128|192|256) ;;
*) echo "$SCRIPTNAME: invalid AES key size $SIZE"; exit 1 ;;
esac
case "$MODE" in
-1) MODE="GCM"
PADDING="NoPadding";;
"CTR"|"GCM") case "$PADDING" in
-1|"NoPadding") PADDING="NoPadding" ;;
*) echo "$SCRIPTNAME: invalid padding AES/$MODE/$PADDING"
exit 1 ;;
esac ;;
"CBC"|"ECB") case "$PADDING" in
-1|"PKCS7Padding") PADDING="PKCS7Padding" ;;
*) echo "$SCRIPTNAME: invalid padding AES/$MODE/$PADDING"
exit 1 ;;
esac ;;
*) echo "$SCRIPTNAME: invalid AES mode $MODE"; exit 1 ;;
esac ;;
*) echo "$SCRIPTNAME: invalid algorithm $ALGORITHM"; exit 1 ;;
esac
if [ "$PURPOSES" -eq -1 ]; then
case "$MODE" in
"-1") PURPOSES="4|8" ;; # Sign+Verify for Pairs
*) case "$ALGORITHM" in
"AES") PURPOSES="1|2" ;; # Encrypt+Decrypt for Ciphers
"RSA") PURPOSES="1|2|4|8" ;;
esac ;;
esac
fi
if [ -z "${QUIET:+1}" ]; then
_ALGORITHM="$ALGORITHM/$MODE/$PADDING"
echo "Algorithm: ${_ALGORITHM%%/-1*}"
echo "Size: $SIZE"
echo "Purposes: $PURPOSES"
fi
$CMD_BASE -e command generate -e alias "$ALIAS" -e algorithm "$ALGORITHM" \
--ei purposes "$(($PURPOSES))" --esa digests NONE,SHA-1,SHA-256,SHA-384,SHA-512 \
--ei size "$SIZE" -e mode "$MODE" -e padding "$PADDING" --ei unlocked "$UNLOCKED" \
--ei validity "$VALIDITY" --ei invalidate "$INVALIDATE" --ei auth "$AUTH"
}
ACTION="${1-}"
if [ "$#" -gt 0 ]; then shift; fi
case "$ACTION" in
list) list_Data "$@" ;;
generate) generate_key "$@" ;;
delete) delete_data "$@" ;;
sign) sign_data "$@" ;;
verify) verify_data "$@" ;;
encrypt) encrypt_data "$@" ;;
decrypt) decrypt_data "$@" ;;
*) show_usage ;;
esac