def rsa_verify(K, h: bytes, sig: bytes) -> bool: # NB: our int_to_bytes() does not output leading 0s (so we prepend 1) h1 = b'\x00' + int_to_bytes(rsalib.decrypt(K, int.from_bytes(sig, 'big'))) print('Decrypted hash:', h1) # bad verif.: we only check a prefix of the decrypted data pref = b'\x00\x01\xff*\x00' + re.escape(ASN1 + h) return re.match(pref, h1) is not None
def main_6_47(): global k, _k, K k = 1 << 5 # byte length of the key (article notation) _k, K = rsalib.gen_key(8 * k) print(f'Key size = {K.n.bit_length()}') _MSG = b'kick it, CC' CIPH = rsalib.encrypt(K, int.from_bytes(_MSG, 'big')) deciph = int_to_bytes(attack(CIPH)) # attack print(f'\n{deciph}') assert deciph == _MSG
def forge_sig(K, h: bytes) -> bytes: assert K.e == 3 s = b'\x00\x01\xff\x00' + ASN1 + h # we triple the size of the signature by padding with garbage s += get_random_bytes(2 * (len(s) + 1)) # we take an approx. integer cube root (as s is not likely a perfect cube) r = rsalib.root3(int.from_bytes(s, 'big')) # r^3 does not reach the modulus assert r**3 <= K.n # its bits will start with the target signature return int_to_bytes(r)
def rsa_sign(k, h: bytes) -> bytes: ph = pkcs115_pad(k.n.bit_length() - 1, h) return int_to_bytes(rsalib.encrypt(k, int.from_bytes(ph, 'big')))
CIPH = rsalib.encrypt(K, _MSG) def odd_oracle(x: int): return rsalib.decrypt(_k, x) & 1 ## Attack c2 = CIPH # = m^e mod n p2 = rsalib.encrypt(K, 2) # = 2^e mod n decimal.getcontext().prec = K.n.bit_length()//3 l, r = decimal.Decimal(0), decimal.Decimal(K.n-1) d2 = decimal.Decimal(2) for i in range(K.n.bit_length()): c2 = (p2*c2) % K.n # let d(i) = decrypted c2(i) # = (2^i * msg) mod n # if 2*d(i) < n, d(i) = 2*d(i-1) even # if 2*d(i) >=n, d(i) = 2*d(i-1) - n odd # as n is odd (and not prime as the statement says...) if odd_oracle(c2): l = (l+r)/d2 else: r = (l+r)/d2 # progress output if i&7==0: mr = bytes(takewhile((lambda c: 32<=c<127), int_to_bytes(int(r)))) print('>', mr.decode(), end='\r') msg = int(r) assert msg == _MSG print(int_to_bytes(msg))
# with 0 <= m < n1,n2,n3 # hence 0 <= m^3 < n1*n2*n3 # hence c123 exactly is m^3 !! # 1. Use Python decimals to compute the cube root #from decimal import Decimal, getcontext #getcontext().prec = c123.bit_length()//3 #m1 = round(Decimal(c123)**(Decimal(1)/Decimal(3))) # 2. Compute integer cube root via Newton's method def root3(c: int) -> int: # Newton's method with integers # f(x) = x^3 - c # f'(x) = 3x^2 x = x0 = 1 + (1 << (c.bit_length() // 3)) x -= (x**3 - c) // (3 * x**2) while x != x0: x0 = x x2 = x * x x -= (x2 * x - c) // (3 * x2) x -= 1 assert x**3 == c return x m1 = root3(c123) mess1 = int_to_bytes(m1) print(mess1, hex(m1)) assert mess1 == mess0
class Server: def __init__(self): self.k, self.K = rsalib.gen_key(1<<10) self.Seen = {} def decrypt(self, c): assert c not in self.Seen self.Seen[c] = time.time() return rsalib.decrypt(self.k, c) if __name__=='__main__': S = Server() e, n = K = S.K mess0 = b'platypus:'+base64.b64encode(get_random_bytes(12)) m0 = int.from_bytes(mess0, 'big') print(mess0, hex(m0)) c0 = rsalib.encrypt(K, m0) # intercepted print('Server:', hex(S.decrypt(c0))) s = randint(2, n-1) c1 = (pow(s, e, n) * c0) % n # c1 = s^e * c0 = (s*m)^e # c1^d = s*m m1 = S.decrypt(c1) m2 = (m1 * pow(s, -1, n)) % n mess2 = int_to_bytes(m2) print(mess2, hex(m2)) assert mess2 == mess0