Fix factory-reset.
[gnuk/gnuk.git] / tests / rsa_keys.py
1 from binascii import hexlify, unhexlify
2 from time import time
3 from struct import pack
4 from hashlib import sha1, sha256
5 import string
6 from os import urandom
7
8 def read_key_from_file(file):
9     f = open(file)
10     n_str = f.readline()[:-1]
11     e_str = f.readline()[:-1]
12     p_str = f.readline()[:-1]
13     q_str = f.readline()[:-1]
14     f.close()
15     e = int(e_str, 16)
16     p = int(p_str, 16)
17     q = int(q_str, 16)
18     n = int(n_str, 16)
19     if n != p * q:
20         raise ValueError("wrong key", p, q, n)
21     return (unhexlify(n_str), unhexlify(e_str), unhexlify(p_str), unhexlify(q_str), e, p, q, n)
22
23 def calc_fpr(n,e):
24     timestamp = int(time())
25     timestamp_data = pack('>I', timestamp)
26     m_len = 6 + 2 + 256 + 2 + 4
27     m = b'\x99' + pack('>H', m_len) + b'\x04' + timestamp_data + b'\x01' + \
28         pack('>H', 2048) + n + pack('>H', 17) + e
29     fpr = sha1(m).digest()
30     return (fpr, timestamp_data)
31
32 key = [ None, None, None ]
33 fpr = [ None, None, None ]
34 timestamp = [ None, None, None ]
35
36 key[0] = read_key_from_file('rsa-sig.key')
37 key[1] = read_key_from_file('rsa-dec.key')
38 key[2] = read_key_from_file('rsa-aut.key')
39
40 (fpr[0], timestamp[0]) = calc_fpr(key[0][0], key[0][1])
41 (fpr[1], timestamp[1]) = calc_fpr(key[1][0], key[1][1])
42 (fpr[2], timestamp[2]) = calc_fpr(key[2][0], key[2][1])
43
44 def build_privkey_template(openpgp_keyno, keyno):
45     n_bytes = key[keyno][0]
46     e_bytes = b'\x00' + key[keyno][1]
47     p_bytes = key[keyno][2]
48     q_bytes = key[keyno][3]
49
50     if openpgp_keyno == 1:
51         keyspec = b'\xb6'
52     elif openpgp_keyno == 2:
53         keyspec = b'\xb8'
54     else:
55         keyspec = b'\xa4'
56
57     key_template = b'\x91\x04'+ b'\x92\x81\x80' + b'\x93\x81\x80' 
58
59     exthdr = keyspec + b'\x00' + b'\x7f\x48' + b'\x08' + key_template
60
61     suffix = b'\x5f\x48' + b'\x82\x01\x04'
62
63     t = b'\x4d' + b'\x82\x01\x16' + exthdr + suffix + e_bytes + p_bytes + q_bytes
64     return t
65
66 def build_privkey_template_for_remove(openpgp_keyno):
67     if openpgp_keyno == 1:
68         keyspec = b'\xb6'
69     elif openpgp_keyno == 2:
70         keyspec = b'\xb8'
71     else:
72         keyspec = b'\xa4'
73     return b'\x4d\02' + keyspec + b'\0x00'
74
75 def compute_digestinfo(msg):
76     digest = sha256(msg).digest()
77     prefix = b'\x30\31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20'
78     return prefix + digest
79
80 # egcd and modinv are from wikibooks
81 # https://en.wikibooks.org/wiki/Algorithm_Implementation/Mathematics/Extended_Euclidean_algorithm
82
83 def egcd(a, b):
84     if a == 0:
85         return (b, 0, 1)
86     else:
87         g, y, x = egcd(b % a, a)
88         return (g, x - (b // a) * y, y)
89
90 def modinv(a, m):
91     g, x, y = egcd(a, m)
92     if g != 1:
93         raise Exception('modular inverse does not exist')
94     else:
95         return x % m
96
97 def pkcs1_pad_for_sign(digestinfo):
98     byte_repr = b'\x00' + b'\x01' + bytes.ljust(b'', 256 - 19 - 32 - 3, b'\xff') \
99         + b'\x00' + digestinfo
100     return int(hexlify(byte_repr), 16)
101
102 def pkcs1_pad_for_crypt(msg):
103     padlen = 256 - 3 - len(msg)
104     byte_repr = b'\x00' + b'\x02' \
105         + bytes.replace(urandom(padlen), b'\x00', b'\x01') + b'\x00' + msg
106     return int(hexlify(byte_repr), 16)
107
108 def compute_signature(keyno, digestinfo):
109     e = key[keyno][4]
110     p = key[keyno][5]
111     q = key[keyno][6]
112     n = key[keyno][7]
113     p1 = p - 1
114     q1 = q - 1
115     h = p1 * q1
116     d = modinv(e, h)
117     dp = d % p1
118     dq = d % q1
119     qp = modinv(q, p)
120
121     input = pkcs1_pad_for_sign(digestinfo)
122     t1 = pow(input, dp, p)
123     t2 = pow(input, dq, q)
124     t = ((t1 - t2) * qp) % p
125     sig = t2 + t * q
126     return sig
127
128 def integer_to_bytes_256(i):
129     return i.to_bytes(256, byteorder='big')
130
131 def encrypt(keyno, plaintext):
132     e = key[keyno][4]
133     n = key[keyno][7]
134     m = pkcs1_pad_for_crypt(plaintext)
135     return b'\x00' + integer_to_bytes_256(pow(m, e, n))
136
137 def encrypt_with_pubkey(pubkey_info, plaintext):
138     n = int(hexlify(pubkey_info[0]), 16)
139     e = int(hexlify(pubkey_info[1]), 16)
140     m = pkcs1_pad_for_crypt(plaintext)
141     return b'\x00' + integer_to_bytes_256(pow(m, e, n))
142
143 def verify_signature(pubkey_info, digestinfo, sig):
144     n = int(hexlify(pubkey_info[0]), 16)
145     e = int(hexlify(pubkey_info[1]), 16)
146     di_pkcs1 = pow(sig,e,n)
147     m = pkcs1_pad_for_sign(digestinfo)
148     return di_pkcs1 == m