def merkle_hellman_modulo(c, pub, modulo): """ Attack to Knapsack Cipher: Lattice Attack with Modulus Args: c : Ciphertext pub : Public key list modulo : Modulo Return: Plaintext """ from scryptos.math import modinv, LLL import random mat = [] pub = pub + [c] for x in xrange(len(pub)): mat += [[0] * x + [1] + [0] * (len(pub) - x - 1) + [pub[x]]] mat += [[0] * (len(pub)) + [modulo]] ml = LLL(mat) # find shortest vector(a.k.a. plaintext) for x in ml: if x[-1] == 0: if x[-2] != -1: if x[-2] == 1: return [(y * modinv(-1, modulo)) % modulo for y in x[:-2]] return [(y * modinv(x[-2], modulo)) % modulo for y in x[:-2]] else: return x[:-2]
def merkle_hellman_low_density_LO(c, pub): """ Attack to Merkle-Hellman Knapsack Cipher: Low-Density Attack using Lagarias-Odlyzko Algorithm Args: c : Ciphertext pub : Public key list Return: Plaintext """ from scryptos.math import LLL mat = [] for x in xrange(len(pub)): mat += [[0] * x + [1] + [0] * (len(pub) - x - 1) + [pub[x]]] mat += [[0] * (len(pub)) + [-c]] ml = LLL(mat) # find shortest vector(a.k.a. plaintext) for x in ml: if all([r == 0 or r == 1 for r in x[:len(pub)]]): # found! ret = "" for y in x[:len(pub)]: if y == 0: ret += "0" elif y == 1: ret += "1" return int(ret, 2)
def common_private_exponent(rsa_list): """ Attack to RSA: Common Private-Exponent Attack Args: rsa_list : RSA Object List (They have a same private exponent) Return: Private Exponent Reference: http://ijcsi.org/papers/IJCSI-9-2-1-311-314.pdf """ from scryptos.math import LLL import math import gmpy eset = map(lambda x: x.e, rsa_list) nset = map(lambda x: x.n, rsa_list) r = len(eset) M = int(gmpy.floor(gmpy.sqrt(nset[-1]))) B = [] B += [[M] + eset] for x in xrange(r): B += [[0] * (x + 1) + [-nset[x]] + [0] * (r - x - 1)] S = LLL(B) d = abs(S[0][0]) / M return d
def Rational_LLL(M, impl="auto"): """ Calculate LLL-reduced Matrix on Rational Field Args: M : A matrix impl : LLL Implementation (default: auto) You can select implementation: auto, fplll, parigp or gap Return: LLL-reduced Matrix Matrix Element Format: (num, denom) """ from scryptos.math import gcd g = None for i in xrange(len(M)): for j in xrange(len(M[i])): if isinstance(M[i][j], (int, long)): continue if M[i][j][1] == 1: continue if g is None: g = M[i][j][1] else: g = gcd(g, M[i][j][1]) for i in xrange(len(M)): for j in xrange(len(M[i])): if isinstance(M[i][j], (int, long)): M[i][j] = M[i][j] * g else: M[i][j] = M[i][j][0] * (g/M[i][j][1]) B = LLL(M) for i in xrange(len(B)): for j in xrange(len(B[i])): p, q = (B[i][j], g) p, q = (p / gcd(p, q), q / gcd(p, q)) if q == 1: B[i][j] = p else: B[i][j] = (p, q) return B
def Orthogonal_Lattice(vs): """ From: `Merkle-Hellman Revisited: A Cryptanalysis of the Qu-Vanstone Cryptosystem Based on Group Factorizations` - Algorithm 5 Reference implementation: https://gist.github.com/hellman/350bed296fc66bcb128dcf7da014684e """ from scryptos.math import vector_norm_i, vector_dot_product, LLL n = len(vs[0]) d = len(vs) c = 2**((n-1)/2 + (n-d)*(n-d-1)/4) c = c * reduce(lambda x,y:x*vector_norm_i(y), vs, 1) M = [] for i in xrange(n): a = [] for j in xrange(d): a += [c * vs[j][i]] a += [0] * i + [1] + [0] * (n-i-1) M += [a] B = LLL(M) # perspective map res = [r[-n:] for r in B] res = res[:n-d] for r in res: assert all(vector_dot_product(r, v) == 0 for v in vs) return res