8
8
https://github.com/aosp-mirror/platform_system_core/blob/c55fab4a59cfa461857c6a61d8a0f1ae4591900c/libcrypto_utils/android_pubkey.c
9
9
10
10
typedef struct RSAPublicKey {
11
- // Modulus length. This must be ANDROID_PUBKEY_MODULUS_SIZE.
11
+ // Modulus length. This must be ANDROID_PUBKEY_MODULUS_SIZE_WORDS
12
12
uint32_t modulus_size_words;
13
13
14
14
// Precomputed montgomery parameter: -1 / n[0] mod 2^32
15
15
uint32_t n0inv;
16
16
17
- // RSA modulus as a little-endian array.
17
+ // RSA modulus as a little-endian array
18
18
uint8_t modulus[ANDROID_PUBKEY_MODULUS_SIZE];
19
19
20
- // Montgomery parameter R^2 as a little-endian array of little-endian words.
20
+ // Montgomery parameter R^2 as a little-endian array of little-endian words
21
21
uint8_t rr[ANDROID_PUBKEY_MODULUS_SIZE];
22
22
23
23
// RSA modulus: 3 or 65537
28
28
from __future__ import print_function
29
29
30
30
import os
31
- import six
32
31
import base64
33
32
import socket
34
33
import struct
40
39
# Size of an RSA modulus such as an encrypted block or a signature.
41
40
ANDROID_PUBKEY_MODULUS_SIZE = (2048 // 8 )
42
41
43
- # Size of an encoded RSA key.
44
- ANDROID_PUBKEY_ENCODED_SIZE = \
45
- (3 * 4 + 2 * ANDROID_PUBKEY_MODULUS_SIZE )
46
- # (3 * sizeof(uint32_t) + 2 * ANDROID_PUBKEY_MODULUS_SIZE)
42
+ # Python representation of "struct RSAPublicKey":
43
+ ANDROID_RSAPUBLICKEY_STRUCT = (
44
+ '<' # Little-endian
45
+ 'L' # uint32_t modulus_size_words;
46
+ 'L' # uint32_t n0inv;
47
+ '{modulus_size}s' # uint8_t modulus[ANDROID_PUBKEY_MODULUS_SIZE];
48
+ '{modulus_size}s' # uint8_t rr[ANDROID_PUBKEY_MODULUS_SIZE];
49
+ 'L' # uint32_t exponent;
50
+ ).format (modulus_size = ANDROID_PUBKEY_MODULUS_SIZE )
51
+
47
52
48
53
# Size of the RSA modulus in words.
49
54
ANDROID_PUBKEY_MODULUS_SIZE_WORDS = (ANDROID_PUBKEY_MODULUS_SIZE // 4 )
52
57
def _to_bytes (n , length , endianess = 'big' ):
53
58
"""partial python2 compatibility with int.to_bytes
54
59
https://stackoverflow.com/a/20793663"""
55
- if six . PY2 :
60
+ if not hasattr ( n , 'to_bytes' ) :
56
61
h = '{:x}' .format (n )
57
62
s = ('0' * (len (h ) % 2 ) + h ).zfill (length * 2 ).decode ('hex' )
58
63
return s if endianess == 'big' else s [::- 1 ]
@@ -62,16 +67,11 @@ def _to_bytes(n, length, endianess='big'):
62
67
def decode_pubkey (public_key ):
63
68
"""decodes a public RSA key stored in Android's custom binary format"""
64
69
binary_key_data = base64 .b64decode (public_key )
65
- key_struct = struct .unpack (('<LL' +
66
- 'B' * ANDROID_PUBKEY_MODULUS_SIZE +
67
- 'B' * ANDROID_PUBKEY_MODULUS_SIZE +
68
- 'L' ), binary_key_data )
69
- modulus_size_words = key_struct [0 ]
70
- n0inv = key_struct [1 ]
71
- modulus = reversed (key_struct [2 : 2 + ANDROID_PUBKEY_MODULUS_SIZE ])
72
- rr = reversed (key_struct [2 + ANDROID_PUBKEY_MODULUS_SIZE :
73
- 2 + 2 * ANDROID_PUBKEY_MODULUS_SIZE ])
74
- exponent = key_struct [- 1 ]
70
+ modulus_size_words , n0inv , modulus_bytes , rr_bytes , exponent = \
71
+ struct .unpack (ANDROID_RSAPUBLICKEY_STRUCT , binary_key_data )
72
+ assert modulus_size_words == ANDROID_PUBKEY_MODULUS_SIZE_WORDS
73
+ modulus = reversed (modulus_bytes )
74
+ rr = reversed (rr_bytes )
75
75
print ('modulus_size_words:' , hex (modulus_size_words ))
76
76
print ('n0inv:' , hex (n0inv ))
77
77
print ('modulus: ' , end = '' )
@@ -83,15 +83,13 @@ def decode_pubkey(public_key):
83
83
84
84
def decode_pubkey_file (public_key_path ):
85
85
with open (public_key_path , 'rb' ) as fd :
86
- decode_pubkey (fd .read ())
86
+ decode_pubkey (fd .read ())
87
87
88
88
89
89
def encode_pubkey (private_key_path ):
90
90
"""encodes a public RSA key into Android's custom binary format"""
91
91
key = Crypto .PublicKey .RSA .import_key (private_key_path )
92
92
93
- # Store the modulus size.
94
- key_buffer = struct .pack ('<L' , ANDROID_PUBKEY_MODULUS_SIZE_WORDS )
95
93
# Compute and store n0inv = -1 / N[0] mod 2^32.
96
94
# BN_set_bit(r32, 32)
97
95
r32 = 1 << 32
@@ -101,19 +99,21 @@ def encode_pubkey(private_key_path):
101
99
n0inv = Crypto .Util .number .inverse (n0inv , r32 )
102
100
# BN_sub(n0inv, r32, n0inv)
103
101
n0inv = r32 - n0inv
104
- key_buffer += struct .pack ('<L' , n0inv )
105
102
106
- # Store the modulus.
107
- key_buffer += _to_bytes (key .n , ANDROID_PUBKEY_MODULUS_SIZE , 'little' )
108
103
# Compute and store rr = (2^(rsa_size)) ^ 2 mod N.
109
104
# BN_set_bit(rr, ANDROID_PUBKEY_MODULUS_SIZE * 8)
110
105
rr = 1 << (ANDROID_PUBKEY_MODULUS_SIZE * 8 )
111
106
# BN_mod_sqr(rr, rr, key->n, ctx)
112
107
rr = (rr ** 2 ) % key .n
113
- key_buffer += _to_bytes (rr , ANDROID_PUBKEY_MODULUS_SIZE , 'little' )
114
108
115
- key_buffer += struct .pack ('<L' , key .e )
116
- return key_buffer
109
+ return struct .pack (
110
+ ANDROID_RSAPUBLICKEY_STRUCT ,
111
+ ANDROID_PUBKEY_MODULUS_SIZE_WORDS ,
112
+ n0inv ,
113
+ _to_bytes (key .n , ANDROID_PUBKEY_MODULUS_SIZE , 'little' ),
114
+ _to_bytes (rr , ANDROID_PUBKEY_MODULUS_SIZE , 'little' ),
115
+ key .e
116
+ )
117
117
118
118
119
119
def get_user_info ():
@@ -135,7 +135,7 @@ def write_public_keyfile(private_key_path, public_key_path):
135
135
private_key = private_key_file .read ()
136
136
137
137
public_key = encode_pubkey (private_key )
138
- assert len (public_key ) == ANDROID_PUBKEY_ENCODED_SIZE
138
+ assert len (public_key ) == struct . calcsize ( ANDROID_RSAPUBLICKEY_STRUCT )
139
139
with open (public_key_path , 'wb' ) as public_key_file :
140
140
public_key_file .write (base64 .b64encode (public_key ))
141
141
public_key_file .write (get_user_info ().encode ())
0 commit comments