def _2user(): # 1st user exp1 = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) public1 = nacl.crypto_scalarmult_curve25519_base(exp1) # print "public1: \t%s\nexp1: \t%s" % (b85encode(public1), b85encode(exp1)) print # 2nd user exp2 = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) public2 = nacl.crypto_scalarmult_curve25519_base(exp2) key = nacl.crypto_scalarmult_curve25519(exp2, public1) print "key: \t%s" % (b85encode(key)) # print "public2: \t%s\nkey: \t%s" % (b85encode(public2), b85encode(key)) print # 1st user completing DH key = nacl.crypto_scalarmult_curve25519(exp1, public2) print "key: \t%s" % (b85encode(key))
def send(self,plain): # update context if self.peer_pub != (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES): # calculate a new incoming key, and finish that DH, start a new for # outgoing keys. # only do this directly after receiving a packet, not on later sends # without receiving any acks before, we reset peer_pub to signal, that # an incoming request has been already once processed like this. self.e_in = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) self.in_prev = self.in_k self.in_k = nacl.crypto_scalarmult_curve25519(self.e_in, self.peer_pub) self.peer_pub = (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES) # generate e_out self.e_out = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) elif self.out_k == (b'\0' * nacl.crypto_secretbox_KEYBYTES): # only for the very first packet necessary # we explicitly need to generate e_out self.e_out = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) #else: # axolotlize # print 'axolotl!' # self.out_k = nacl.crypto_generichash(self.out_k, # nacl.crypto_scalarmult_curve25519(self.me_id.cs, self.peer_id.cp), # nacl.crypto_scalarmult_curve25519_BYTES) # compose packet dh1 = nacl.crypto_scalarmult_curve25519_base(self.e_out) dh2 = (nacl.crypto_scalarmult_curve25519_base(self.e_in) if self.e_in != (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES) else (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES)) plain = b''.join((dh1, dh2, plain)) # encrypt the whole packet return self.encrypt(plain)
def mpecdh(self, keyring=[]): if self.secret: return self.secret if not self.key: self.key = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) keyring = [nacl.crypto_scalarmult_curve25519(self.key, public) for public in keyring] keyring.append(nacl.crypto_scalarmult_curve25519_base(self.key)) if len(keyring) == self.peers: # we are last, remove our own secret self.secret = keyring[0] keyring = keyring[1:] else: self.secret = nacl.crypto_scalarmult_curve25519(self.key, keyring[0]) keyring = [nacl.crypto_scalarmult_curve25519(self.key, public) for public in keyring[1:]] clearmem(self.key) self.key = None self.next.mpecdh(keyring)
def blake2b(self, data, addr, server=False): # ECDH_AED_accept = None addrStr = sts_utility.addrToString(addr) proposeResp = sts_utility.deconstructPropose(data) # print(STS.STSConnectionStates) # if addrStr in STS.STSConnectionStates.keys(): myECDHPK, myECDHSK = STS.STSConnectionStates[addrStr]['keys'] # TODO verification scalarmult_q = pysodium.crypto_scalarmult_curve25519( myECDHSK, proposeResp['K']) genericHash = pysodium.crypto_generichash_init(outlen=64) genericHash = pysodium.crypto_generichash_update( genericHash, scalarmult_q) if not server: genericHash = pysodium.crypto_generichash_update( genericHash, myECDHPK) genericHash = pysodium.crypto_generichash_update( genericHash, proposeResp['K']) else: genericHash = pysodium.crypto_generichash_update( genericHash, proposeResp['K']) genericHash = pysodium.crypto_generichash_update( genericHash, myECDHPK) genericHash = pysodium.crypto_generichash_final(genericHash, outlen=64) STS.STSConnectionStates[addrStr]['session_key'] = genericHash # STS.STSConnectionStates[addrStr]['phase'] = 1 STS.STSConnectionStates[addrStr]['time'] = int(time.time())
def send(self, plain): # update context if self.peer_pub != (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES): # calculate a new incoming key, and finish that DH, start a new for # outgoing keys. # only do this directly after receiving a packet, not on later sends # without receiving any acks before, we reset peer_pub to signal, that # an incoming request has been already once processed like this. self.e_in = nacl.randombytes( nacl.crypto_scalarmult_curve25519_BYTES) self.in_prev = self.in_k self.in_k = nacl.crypto_scalarmult_curve25519( self.e_in, self.peer_pub) self.peer_pub = (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES) # generate e_out self.e_out = nacl.randombytes( nacl.crypto_scalarmult_curve25519_BYTES) elif self.out_k == (b'\0' * nacl.crypto_secretbox_KEYBYTES): # only for the very first packet necessary # we explicitly need to generate e_out self.e_out = nacl.randombytes( nacl.crypto_scalarmult_curve25519_BYTES) # compose packet dh1 = nacl.crypto_scalarmult_curve25519_base(self.e_out) dh2 = (nacl.crypto_scalarmult_curve25519_base(self.e_in) if self.e_in != (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES) else (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES)) plain = b''.join((dh1, dh2, plain)) # encrypt the whole packet return self.encrypt(plain)
def _2user(): # 1st user exp1 = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) public1 = nacl.crypto_scalarmult_curve25519_base(exp1) #print("public1: \t%s\nexp1: \t%s" % (b85encode(public1), b85encode(exp1))) print() # 2nd user exp2 = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) public2 = nacl.crypto_scalarmult_curve25519_base(exp2) key = nacl.crypto_scalarmult_curve25519(exp2, public1) print("key: \t%s" % (b85encode(key))) #print("public2: \t%s\nkey: \t%s" % (b85encode(public2), b85encode(key))) print() # 1st user completing DH key = nacl.crypto_scalarmult_curve25519(exp1, public2) print("key: \t%s" % (b85encode(key)))
def mpecdh(self, keyring = []): if self.secret: return self.secret if not self.key: self.key = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) keyring = [nacl.crypto_scalarmult_curve25519(self.key, public) for public in keyring] keyring.append(nacl.crypto_scalarmult_curve25519_base(self.key)) if len(keyring) == self.peers: # we are last, remove our own secret self.secret = keyring[0] keyring = keyring[1:] else: self.secret = nacl.crypto_scalarmult_curve25519(self.key, keyring[0]) keyring = [nacl.crypto_scalarmult_curve25519(self.key, public) for public in keyring[1:]] clearmem(self.key) self.key = None self.next.mpecdh(keyring)
def dh2_handler(peer): # provides a high level interface to receive a DH key exchange # request peer contains the public component generated by the peer # when initiating an DH exchange exp = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) public = nacl.crypto_scalarmult_curve25519_base(exp) secret = nacl.crypto_scalarmult_curve25519(exp, peer) return (public, secret)
def dh2_handler(peer): # provides a high level interface to receive a DH key exchange # request peer contains the public component generated by the peer # when initiating an DH exchange exp = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) public = nacl.crypto_scalarmult_curve25519_base(exp) secret = nacl.crypto_scalarmult_curve25519(exp, b85decode(peer)) return (public, secret)
def mpecdh1(self, keyring = []): self.key = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) keyring = [nacl.crypto_scalarmult_curve25519(self.key, public) for public in keyring] keyring.append(nacl.crypto_scalarmult_curve25519_base(self.key)) if len(keyring) == int(self.peers): # we are last, remove our own secret self.secret = keyring[0] keyring = keyring[1:] return keyring
def dh2_handler(peer): exp = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) public = nacl.crypto_scalarmult_curve25519_base(exp) (sys.stdout.buffer if hasattr(sys.stdout, 'buffer') else sys.stdout).write(b"public component " + b85encode(public) + b'\n') secret = nacl.crypto_scalarmult_curve25519(exp, b85decode(peer)) (sys.stdout.buffer if hasattr(sys.stdout, 'buffer') else sys.stdout).write(b"shared secret " + b85encode(secret) + b'\n') clearmem(secret) clearmem(exp)
def receive(self, cipher, nonce): # decrypt the packet plain = self.decrypt(cipher, nonce) # update context self.peer_pub=plain[:nacl.crypto_scalarmult_curve25519_BYTES] if self.e_out != (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES): dh2=plain[nacl.crypto_scalarmult_curve25519_BYTES:nacl.crypto_scalarmult_curve25519_BYTES*2] self.out_k = nacl.crypto_scalarmult_curve25519(self.e_out, dh2) return plain[nacl.crypto_scalarmult_curve25519_BYTES*2:]
def receive(self, cipher, nonce): # decrypt the packet plain = self.decrypt(cipher, nonce) # update context self.peer_pub = plain[:nacl.crypto_scalarmult_curve25519_BYTES] if self.e_out != (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES): dh2 = plain[nacl.crypto_scalarmult_curve25519_BYTES:nacl. crypto_scalarmult_curve25519_BYTES * 2] self.out_k = nacl.crypto_scalarmult_curve25519(self.e_out, dh2) return plain[nacl.crypto_scalarmult_curve25519_BYTES * 2:]
def keyExchange(us, them, extra): """ do key exchange """ q = pysodium.crypto_scalarmult_curve25519(us, them) h = blake2b(digest_size=pysodium.crypto_aead_chacha20poly1305_KEYBYTES) h.update(q) h.update(us) h.update(them) h.update(extra) return h.digest()
def _3user(): eA = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) pA = nacl.crypto_scalarmult_curve25519_base(eA) print "A public: \t%s\nA exp: \t%s" % (b85encode(pA), b85encode(eA)) eB = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) pB = nacl.crypto_scalarmult_curve25519_base(eB) print "B public: \t%s\nB exp: \t%s" % (b85encode(pB), b85encode(eB)) eC = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) pC = nacl.crypto_scalarmult_curve25519_base(eC) print "C public: \t%s\nC exp: \t%s" % (b85encode(pC), b85encode(eC)) print pAB = nacl.crypto_scalarmult_curve25519(eB, pA) print "public AB", b85encode(pAB) pBA = nacl.crypto_scalarmult_curve25519(eA, pB) print "public BA", b85encode(pBA) pCA = nacl.crypto_scalarmult_curve25519(eA, pC) print "public CA", b85encode(pCA) print key = nacl.crypto_scalarmult_curve25519(eB, pCA) print "key: \t%s" % (b85encode(key)) key = nacl.crypto_scalarmult_curve25519(eC, pBA) print "key: \t%s" % (b85encode(key)) key = nacl.crypto_scalarmult_curve25519(eC, pAB) print "key: \t%s" % (b85encode(key))
def _3user(): eA = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) pA = nacl.crypto_scalarmult_curve25519_base(eA) print("A public: \t%s\nA exp: \t%s" % (b85encode(pA), b85encode(eA))) eB = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) pB = nacl.crypto_scalarmult_curve25519_base(eB) print("B public: \t%s\nB exp: \t%s" % (b85encode(pB), b85encode(eB))) eC = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) pC = nacl.crypto_scalarmult_curve25519_base(eC) print("C public: \t%s\nC exp: \t%s" % (b85encode(pC), b85encode(eC))) print() pAB = nacl.crypto_scalarmult_curve25519(eB, pA) print("public AB", b85encode(pAB)) pBA = nacl.crypto_scalarmult_curve25519(eA, pB) print("public BA", b85encode(pBA)) pCA = nacl.crypto_scalarmult_curve25519(eA, pC) print("public CA", b85encode(pCA)) print() key = nacl.crypto_scalarmult_curve25519(eB, pCA) print("key: \t%s" % (b85encode(key))) key = nacl.crypto_scalarmult_curve25519(eC, pBA) print("key: \t%s" % (b85encode(key))) key = nacl.crypto_scalarmult_curve25519(eC, pAB) print("key: \t%s" % (b85encode(key)))
def tripledh(self): """Triple DH performs cross DH between two peers having two keys each: - an identity key (Ai,Bi), and - an ephemeral key (Ae, Be). the cross DH is then performed on these pairs: (Ai,Be)+(Bi,Ae)+(Ae,Be) The order of the parameters to these operations depends on the order in which the peers are acting. """ if self.isalice: p1 = nacl.crypto_scalarmult_curve25519(self.me.identitykey.sk, self.peer['ephemeralkey']) p2 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['identitykey']) p3 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['ephemeralkey']) sec = p1+p2+p3 clearmem(p1) clearmem(p2) clearmem(p3) res = nacl.crypto_generichash(sec, '', nacl.crypto_secretbox_KEYBYTES) clearmem(sec) return res p1 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['identitykey']) p2 = nacl.crypto_scalarmult_curve25519(self.me.identitykey.sk, self.peer['ephemeralkey']) p3 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['ephemeralkey']) sec = p1+p2+p3 clearmem(p1) clearmem(p2) clearmem(p3) res = nacl.crypto_generichash(sec, '', nacl.crypto_secretbox_KEYBYTES) clearmem(sec) return res
def use_epk(self, topic, usage, pks, clear=True): rv = [] if (isinstance(topic,(bytes,bytearray))): self._logger.debug("passed a topic in bytes (should be string)") topic = topic.decode('utf-8') if (isinstance(usage,(bytes,bytearray))): self._logger.debug("passed a usage in bytes (should be string)") usage = usage.decode('utf-8') with self.__eklock: if not topic in self.__esk or not usage in self.__esk[topic]: return rv for pk in pks: rv.append(pysodium.crypto_scalarmult_curve25519(self.__esk[topic][usage],pk)) if clear: self.__remove_esk(topic, usage) return rv
def tripledh(self): """Triple DH performs cross DH between two peers having two keys each: - an identity key (Ai,Bi), and - an ephemeral key (Ae, Be). the cross DH is then performed on these pairs: (Ai,Be)+(Bi,Ae)+(Ae,Be) The order of the parameters to these operations depends on the order in which the peers are acting. """ if self.isalice: p1 = nacl.crypto_scalarmult_curve25519(self.me.identitykey.sk, self.peer['ephemeralkey']) p2 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['identitykey']) p3 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['ephemeralkey']) sec = p1 + p2 + p3 clearmem(p1) clearmem(p2) clearmem(p3) res = nacl.crypto_generichash(sec, '', nacl.crypto_secretbox_KEYBYTES) clearmem(sec) return res p1 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['identitykey']) p2 = nacl.crypto_scalarmult_curve25519(self.me.identitykey.sk, self.peer['ephemeralkey']) p3 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['ephemeralkey']) sec = p1 + p2 + p3 clearmem(p1) clearmem(p2) clearmem(p3) res = nacl.crypto_generichash(sec, '', nacl.crypto_secretbox_KEYBYTES) clearmem(sec) return res
def dh3_handler(public, exp): # finishes the 3 step DH key exchange by combining the public # component of the peer, generated in the 2nd step by the peer, # using the exponent generated when the exchange was initiated. secret = nacl.crypto_scalarmult_curve25519(b85decode(exp), b85decode(public)) return secret
def addpeer(self, point): return nacl.crypto_scalarmult_curve25519(self.key, point)
def dh3_handler(public, exp): # finishes the 3 step DH key exchange by combining the public # component of the peer, generated in the 2nd step by the peer, # using the exponent generated when the exchange was initiated. secret = nacl.crypto_scalarmult_curve25519(exp, public) return secret
def finish(self, point): self.secret = nacl.crypto_scalarmult_curve25519(self.key, point) return self.secret
def test_crypto_scalarmut_curve25519_base(self): s = pysodium.crypto_scalarmult_curve25519_base(pysodium.randombytes(pysodium.crypto_scalarmult_BYTES)) r = pysodium.crypto_scalarmult_curve25519_base(pysodium.randombytes(pysodium.crypto_scalarmult_BYTES)) pysodium.crypto_scalarmult_curve25519(s, r)
def mpecdh2(self, keyring): self.secret = nacl.crypto_scalarmult_curve25519(self.key, keyring[0]) keyring = [nacl.crypto_scalarmult_curve25519(self.key, public) for public in keyring[1:]] return keyring
def test_crypto_scalarmult_curve25519_base(self): s = pysodium.crypto_scalarmult_curve25519_base( pysodium.randombytes(pysodium.crypto_scalarmult_BYTES)) r = pysodium.crypto_scalarmult_curve25519_base( pysodium.randombytes(pysodium.crypto_scalarmult_BYTES)) pysodium.crypto_scalarmult_curve25519(s, r)
def recv(self, msg): """ as per https://github.com/trevp/axolotl/wiki/newversion (Nov 19, 2013 · 41 revisions) Receiving messages ------------------- Local variables: MK : message key Np : Purported message number PNp : Purported previous message number CKp : Purported new chain key DHp : Purported new DHr RKp : Purported new root key NHKp, HKp : Purported new header keys if (plaintext = try_skipped_header_and_message_keys()): return plaintext if Dec(HKr, header): Np = read() CKp, MK = stage_skipped_header_and_message_keys(HKr, Nr, Np, CKr) if not Dec(MK, ciphertext): raise undecryptable if bobs_first_message: DHRr = read() RK = HASH(RK || ECDH(DHRs, DHRr)) HKs = NHKs NHKs, CKs = KDF(RK) erase(DHRs) bobs_first_message = False else: if not Dec(NHKr, header): raise undecryptable() Np, PNp, DHRp = read() stage_skipped_header_and_message_keys(HKr, Nr, PNp, CKr) RKp = HASH(RK || ECDH(DHRs, DHRr)) HKp = NHKr NHKp, CKp = KDF(RKp) CKp, MK = stage_skipped_header_and_message_keys(HKp, 0, Np, CKp) if not Dec(MK, ciphertext): raise undecryptable() RK = RKp HKr = HKp NHKr = NHKp DHRr = DHRp RK = HASH(RK || ECDH(DHRs, DHRr)) HKs = NHKs NHKs, CKs = KDF(RK) erase(DHRs) commit_skipped_header_and_message_keys() Nr = Np + 1 CKr = CKp return read() """ hnonce = msg[:nacl.crypto_secretbox_NONCEBYTES] i = nacl.crypto_secretbox_NONCEBYTES mnonce = msg[i:i + nacl.crypto_secretbox_NONCEBYTES] i += nacl.crypto_secretbox_NONCEBYTES hcrypt = msg[i:i + nacl.crypto_secretbox_MACBYTES + 4 + 4 + nacl.crypto_scalarmult_curve25519_BYTES] i += nacl.crypto_secretbox_MACBYTES + 4 + 4 + nacl.crypto_scalarmult_curve25519_BYTES mcrypt = msg[i:] ret = self.try_skipped_keys(hcrypt, hnonce, mcrypt, mnonce) if ret: return ret headers = None try: headers = nacl.crypto_secretbox_open(hcrypt, hnonce, self.HKr) except: pass if headers: Np = struct.unpack('>I', headers[:4])[0] CKp, MK = self.stage_skipped_keys(self.HKr, self.Nr, Np, self.CKr) msg = nacl.crypto_secretbox_open(mcrypt, mnonce, MK) if self.bobs1stmsg: self.DHRr = headers[8:] self.RK = nacl.crypto_generichash( self.RK, nacl.crypto_scalarmult_curve25519(self.DHRs.sk, self.DHRr), KEY_SIZE) self.HKs = self.NHKs if self.isalice: self.NHKs = nacl.crypto_generichash( self.RK, "NHKs", KEY_SIZE) self.CKs = nacl.crypto_generichash(self.RK, "CKs", KEY_SIZE) else: self.NHKs = nacl.crypto_generichash( self.RK, "NHKr", KEY_SIZE) self.CKs = nacl.crypto_generichash(self.RK, "CKr", KEY_SIZE) self.DHRs.clear() self.DHRs = None self.bobs1stmsg = False else: headers = nacl.crypto_secretbox_open(hcrypt, hnonce, self.NHKr) #unpack header fields Np = struct.unpack('>I', headers[:4])[0] PNp = struct.unpack('>I', headers[4:8])[0] DHRp = headers[8:] self.stage_skipped_keys(self.HKr, self.Nr, PNp, self.CKr) RKp = nacl.crypto_generichash( self.RK, nacl.crypto_scalarmult_curve25519(self.DHRs.sk, self.DHRr), KEY_SIZE) HKp = self.NHKr if self.isalice: NHKp = nacl.crypto_generichash(RKp, "NHKr", KEY_SIZE) CKp = nacl.crypto_generichash(RKp, "CKr", KEY_SIZE) else: NHKp = nacl.crypto_generichash(RKp, "NHKs", KEY_SIZE) CKp = nacl.crypto_generichash(RKp, "CKs", KEY_SIZE) CKp, MK = self.stage_skipped_keys(HKp, 0, Np, CKp) msg = nacl.crypto_secretbox_open(mcrypt, mnonce, MK) self.RK = RKp self.HKr = HKp self.NHKr = NHKp self.DHRr = DHRp self.RK = nacl.crypto_generichash( self.RK, nacl.crypto_scalarmult_curve25519(self.DHRs.sk, self.DHRr), KEY_SIZE) self.HKs = self.NHKs if self.isalice: self.NHKs = nacl.crypto_generichash(self.RK, "NHKs", KEY_SIZE) self.CKs = nacl.crypto_generichash(self.RK, "CKs", KEY_SIZE) else: self.NHKs = nacl.crypto_generichash(self.RK, "NHKr", KEY_SIZE) self.CKs = nacl.crypto_generichash(self.RK, "CKr", KEY_SIZE) self.DHRs.clear() self.DHRs = None # commit_skipped_header_and_message_keys() : Commits any skipped-over message keys from the # staging area to persistent storage (along with their associated header keys). self.skipped_HK_MK.update(self.staged_HK_MK) self.staged_HK_MK = {} self.Nr = Np + 1 self.CKr = CKp return msg
def dh3_handler(public, exp): secret = nacl.crypto_scalarmult_curve25519(b85decode(exp), b85decode(public)) (sys.stdout.buffer if hasattr(sys.stdout, 'buffer') else sys.stdout).write(b"shared secret " + b85encode(secret) + b'\n') clearmem(secret)
def recv(self, msg): """ as per https://github.com/trevp/axolotl/wiki/newversion (Nov 19, 2013 · 41 revisions) Receiving messages ------------------- Local variables: MK : message key Np : Purported message number PNp : Purported previous message number CKp : Purported new chain key DHp : Purported new DHr RKp : Purported new root key NHKp, HKp : Purported new header keys if (plaintext = try_skipped_header_and_message_keys()): return plaintext if Dec(HKr, header): Np = read() CKp, MK = stage_skipped_header_and_message_keys(HKr, Nr, Np, CKr) if not Dec(MK, ciphertext): raise undecryptable if bobs_first_message: DHRr = read() RK = HASH(RK || ECDH(DHRs, DHRr)) HKs = NHKs NHKs, CKs = KDF(RK) erase(DHRs) bobs_first_message = False else: if not Dec(NHKr, header): raise undecryptable() Np, PNp, DHRp = read() stage_skipped_header_and_message_keys(HKr, Nr, PNp, CKr) RKp = HASH(RK || ECDH(DHRs, DHRr)) HKp = NHKr NHKp, CKp = KDF(RKp) CKp, MK = stage_skipped_header_and_message_keys(HKp, 0, Np, CKp) if not Dec(MK, ciphertext): raise undecryptable() RK = RKp HKr = HKp NHKr = NHKp DHRr = DHRp RK = HASH(RK || ECDH(DHRs, DHRr)) HKs = NHKs NHKs, CKs = KDF(RK) erase(DHRs) commit_skipped_header_and_message_keys() Nr = Np + 1 CKr = CKp return read() """ hnonce = msg[:nacl.crypto_secretbox_NONCEBYTES] i = nacl.crypto_secretbox_NONCEBYTES mnonce = msg[i:i+nacl.crypto_secretbox_NONCEBYTES] i += nacl.crypto_secretbox_NONCEBYTES hcrypt = msg[i:i + nacl.crypto_secretbox_MACBYTES + 4 + 4 + nacl.crypto_scalarmult_curve25519_BYTES] i += nacl.crypto_secretbox_MACBYTES + 4 + 4 + nacl.crypto_scalarmult_curve25519_BYTES mcrypt = msg[i:] ret = self.try_skipped_keys(hcrypt, hnonce, mcrypt, mnonce) if ret: return ret headers = None try: headers = nacl.crypto_secretbox_open(hcrypt, hnonce, self.HKr) except: pass if headers: Np = struct.unpack('>I',headers[:4])[0] CKp, MK = self.stage_skipped_keys(self.HKr, self.Nr, Np, self.CKr) msg = nacl.crypto_secretbox_open(mcrypt, mnonce, MK) if self.bobs1stmsg: self.DHRr = headers[8:] self.RK = nacl.crypto_generichash(self.RK, nacl.crypto_scalarmult_curve25519(self.DHRs.sk,self.DHRr), KEY_SIZE) self.HKs = self.NHKs if self.isalice: self.NHKs = nacl.crypto_generichash(self.RK, "NHKs", KEY_SIZE) self.CKs = nacl.crypto_generichash(self.RK, "CKs", KEY_SIZE) else: self.NHKs = nacl.crypto_generichash(self.RK, "NHKr", KEY_SIZE) self.CKs = nacl.crypto_generichash(self.RK, "CKr", KEY_SIZE) self.DHRs.clear() self.DHRs = None self.bobs1stmsg = False else: headers = nacl.crypto_secretbox_open(hcrypt, hnonce, self.NHKr) #unpack header fields Np = struct.unpack('>I',headers[:4])[0] PNp = struct.unpack('>I',headers[4:8])[0] DHRp = headers[8:] self.stage_skipped_keys(self.HKr, self.Nr, PNp, self.CKr) RKp = nacl.crypto_generichash(self.RK, nacl.crypto_scalarmult_curve25519(self.DHRs.sk,self.DHRr), KEY_SIZE) HKp = self.NHKr if self.isalice: NHKp = nacl.crypto_generichash(RKp, "NHKr", KEY_SIZE) CKp = nacl.crypto_generichash(RKp, "CKr", KEY_SIZE) else: NHKp = nacl.crypto_generichash(RKp, "NHKs", KEY_SIZE) CKp = nacl.crypto_generichash(RKp, "CKs", KEY_SIZE) CKp, MK = self.stage_skipped_keys(HKp, 0, Np, CKp) msg = nacl.crypto_secretbox_open(mcrypt, mnonce, MK) self.RK = RKp self.HKr = HKp self.NHKr = NHKp self.DHRr = DHRp self.RK = nacl.crypto_generichash(self.RK, nacl.crypto_scalarmult_curve25519(self.DHRs.sk,self.DHRr), KEY_SIZE) self.HKs = self.NHKs if self.isalice: self.NHKs = nacl.crypto_generichash(self.RK, "NHKs", KEY_SIZE) self.CKs = nacl.crypto_generichash(self.RK, "CKs", KEY_SIZE) else: self.NHKs = nacl.crypto_generichash(self.RK, "NHKr", KEY_SIZE) self.CKs = nacl.crypto_generichash(self.RK, "CKr", KEY_SIZE) self.DHRs.clear() self.DHRs = None # commit_skipped_header_and_message_keys() : Commits any skipped-over message keys from the # staging area to persistent storage (along with their associated header keys). self.skipped_HK_MK.update(self.staged_HK_MK) self.staged_HK_MK = {} self.Nr = Np + 1 self.CKr = CKp return msg