예제 #1
0
 def run(self):
     assert self.outbox is not None
     self.outbox.put((self.mel, self.KA))
     salt, B = self.inbox.get()
     u = int.from_bytes(SHA256.new(int_to_bytes(self.KA)+int_to_bytes(B)).digest(), 'big')
     # using the salt, retrieve the server db entry key
     Kx = int.from_bytes(SHA256.new(salt+self.pwd).digest(), 'big')
     KX = pow(self.g, Kx, self.N)
     sec = pow(B-self.k*KX, self.Ka+u*Kx, self.N)
     # sec = (B-k*KX)^(Ka+u*Kx) = KB^(Ka+u*Kx) = g^(Kb*(Ka+u*Kx))
     key = SHA256.new(int_to_bytes(sec)).digest()
     print('Client: key', key.hex())
     mac = HMAC.new(key, salt, SHA256).digest()
     self.outbox.put(mac)
     ok = self.inbox.get()
     assert ok == b'OK'
     print('Client: ok, done')
예제 #2
0
 def run(self):
     assert self.outbox is not None
     # get client id and retrieve its entry
     mel, KA = self.inbox.get()   
     assert mel in self.DB
     salt, KX = self.DB[mel]
     # B = k*KX + KB
     # linear mix of the pwd "pub." key with the server "pub." key
     B = (self.k*KX + self.KB) % self.N
     self.outbox.put((salt, B))
     u = int.from_bytes(SHA256.new(int_to_bytes(KA)+int_to_bytes(B)).digest(), 'big')
     sec = pow(KA*pow(KX, u, self.N), self.Kb, self.N)
     # sec = g^((Ka+Kx*u)*Kb)
     key = SHA256.new(int_to_bytes(sec)).digest()
     print('Server: key', key.hex())
     mac = self.inbox.get()
     HMAC.new(key, salt, SHA256).verify(mac)
     print('Server: ok')
     self.outbox.put(b'OK')
     print('Server: done')
예제 #3
0
 def run(self):
     assert self.outbox is not None
     p, g, KA = self.inbox.get()
     Kb, KB = dhlib.gen_key(p, g)
     self.outbox.put(KB)
     s = pow(KA, Kb, p)
     key = SHA1.new(int_to_bytes(s)).digest()[:BS]
     ciph, iv = self.inbox.get()
     msg = unpad(AES.new(key, AES.MODE_CBC, iv).decrypt(ciph), BS)
     print('Bob:  ', msg)
     iv = get_random_bytes(BS)
     ciph = AES.new(key, AES.MODE_CBC, iv).encrypt(pad(msg, BS))
     self.outbox.put((ciph, iv))
     print('Bob:   done')
예제 #4
0
 def run(self):
     assert self.outbox is not None
     self.outbox.put((self.p, self.g, self.KA))
     KB = self.inbox.get()
     s = pow(KB, self.Ka, self.p)
     key = SHA1.new(int_to_bytes(s)).digest()[:BS]
     iv = get_random_bytes(BS)
     msg = b'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
     ciph = AES.new(key, AES.MODE_CBC, iv).encrypt(pad(msg, BS))
     self.outbox.put((ciph, iv))
     ciph, iv = self.inbox.get()
     msgB = unpad(AES.new(key, AES.MODE_CBC, iv).decrypt(ciph), BS)
     assert msg == msgB
     print('Alice: msg ok, done')
예제 #5
0
 def attack3_active(self, ciphA, ivA):
     sA = self.p - self.s
     keyA = SHA1.new(int_to_bytes(sA)).digest()[:BS]
     print("Eve:   Alice's key", keyA.hex())
     msg = unpad(AES.new(keyA, AES.MODE_CBC, ivA).decrypt(ciphA), BS)
     print('Eve:  ', msg)
     ciph = AES.new(self.key, AES.MODE_CBC, ivA).encrypt(pad(msg, BS))
     self.outB.put((ciph, ivA))
     ciph, iv = self.inB.get()
     msg = unpad(AES.new(self.key, AES.MODE_CBC, iv).decrypt(ciph), BS)
     print('Eve:  ', msg)
     ciphA = AES.new(keyA, AES.MODE_CBC, iv).encrypt(pad(msg, BS))
     self.outA.put((ciphA, iv))
     print('Eve:   done')
예제 #6
0
 def run(self):
     assert self.outbox is not None
     self.outbox.put((self.p, self.g))
     assert self.inbox.get() == 'ACK'
     self.outbox.put(self.KA)
     KB = self.inbox.get()
     s = pow(KB, self.Ka, self.p)
     key = SHA1.new(int_to_bytes(s)).digest()[:BS]
     print('Alice: key', key.hex())
     iv = get_random_bytes(BS)
     msg = b'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.'
     ciph = AES.new(key, AES.MODE_CBC, iv).encrypt(pad(msg, BS))
     self.outbox.put((ciph, iv))
     ciph, iv = self.inbox.get()
     msgB = unpad(AES.new(key, AES.MODE_CBC, iv).decrypt(ciph), BS)
     assert msg == msgB
     print('Alice: msg ok, done')
예제 #7
0
    def attack3(self):
        print('Eve:   attack 3, g = p-1')
        # In this case, KB = ±1 depending on the parity of Kb.
        # If Kb is even, then KB = 1, s_A = 1 and we can
        # arbitrarily inject KA_B = ±1.
        # If Kb is odd, KB = -1, s_A = ±1 depending on the
        # parity of Ka, and we should inject KA_B = s_A.

        # Prop.: If g is a generator of Zₚ*,
        #        Ka is even <=> KA (= g^Ka) is a square mod p
        #   => trivial
        #   <= KA = x², ∃n / x = gⁿ, KA = g²ⁿ = g^Ka,
        #      hence Ka = 2n mod p-1, with p-1 even,
        #      hence Ka is even
        # In that case, we can use Euler's criterion to test
        # whether KA is a square (and then choose KA_B = ±1).
        # https://en.wikipedia.org/wiki/Euler%27s_criterion

        # Problem: In practice, the given g = 2, probably for
        # optimized computation purposes, and is NOT a primitive
        # root. Even worse, its order might be odd, in which case
        # two Ka of different parity might generate the same KA
        # but different secrets when given KB = -1.
        # Solution: We pick KA_B at random, there is a 1/4 chance
        # to fail (Kb odd & bad choice), in which case we detect
        # if by a padding error and switch to a fully active
        # attack (as A and B do not share the same key).
        self.outB.put((self.p, self.p - 1))  # g_B := p-1 (= -1)
        ack = self.inB.get()
        assert ack == 'ACK'
        self.outA.put(ack)
        KA = self.inA.get()
        # primitive root deterministic case:
        #even_Ka = pow(KA, (p-1)//2, p)==1
        # randomized case:
        even_Ka = randint(0, 1) == 0
        self.outB.put(1 if even_Ka else self.p - 1)
        KB = self.inB.get()
        assert KB == 1 or KB == self.p - 1
        self.outA.put(KB)
        self.s = 1 if KB == 1 or even_Ka else self.p - 1
        self.key = SHA1.new(int_to_bytes(self.s)).digest()[:BS]