def runTest(self): key = b"0" * 16 data = b"\x00\x01\x02" # Data and key can be a bytearray (during initialization) key_ba = bytearray(key) data_ba = bytearray(data) h1 = HMAC.new(key, data) h2 = HMAC.new(key_ba, data_ba) key_ba[:1] = b'\xFF' data_ba[:1] = b'\xFF' self.assertEqual(h1.digest(), h2.digest()) # Data can be a bytearray (during operation) key_ba = bytearray(key) data_ba = bytearray(data) h1 = HMAC.new(key) h2 = HMAC.new(key) h1.update(data) h2.update(data_ba) data_ba[:1] = b'\xFF' self.assertEqual(h1.digest(), h2.digest())
def runTest(self): key = b"0" * 16 data = b"\x00\x01\x02" def get_mv_ro(data): return memoryview(data) def get_mv_rw(data): return memoryview(bytearray(data)) for get_mv in (get_mv_ro, get_mv_rw): # Data and key can be a memoryview (during initialization) key_mv = get_mv(key) data_mv = get_mv(data) h1 = HMAC.new(key, data) h2 = HMAC.new(key_mv, data_mv) if not data_mv.readonly: key_mv[:1] = b'\xFF' data_mv[:1] = b'\xFF' self.assertEqual(h1.digest(), h2.digest()) # Data can be a memoryview (during operation) data_mv = get_mv(data) h1 = HMAC.new(key) h2 = HMAC.new(key) h1.update(data) h2.update(data_mv) if not data_mv.readonly: data_mv[:1] = b'\xFF' self.assertEqual(h1.digest(), h2.digest())
def ComputeResponsev2(NegFlg, ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChallenge, Time=None, ServerName=None, av_pairs=None): if Time is None: Time = nttime.NtTime(nttime.datetime.now()) if ServerName is None: ServerName = "SERVER" ServerName = ServerName.encode("utf-16-le") TimeBuf = array.array("B") cur = core.Cursor(TimeBuf,0) cur.encode_uint64le(Time) Responseversion = "\x01" HiResponseversion = "\x01" ntlmv2_client_challenge = NTLMv2ClientChallenge() ntlmv2_client_challenge.time_stamp = Time ntlmv2_client_challenge.challenge_from_client = ClientChallenge if av_pairs is not None: ntlmv2_client_challenge.av_pairs = av_pairs temp = encode_frame(ntlmv2_client_challenge).tostring() NTProofStr = HMAC.new(ResponseKeyNT, ServerChallenge + temp, MD5).digest() NtChallengeResponse = NTProofStr + temp LmChallengeResponse = HMAC.new(ResponseKeyLM, ServerChallenge + ClientChallenge, MD5).digest() +\ ClientChallenge SessionBaseKey = HMAC.new(ResponseKeyNT, NTProofStr, MD5).digest() return NtChallengeResponse, LmChallengeResponse, SessionBaseKey
def GSS_GetMIC(self, sessionKey, data, sequenceNumber, direction = 'init'): GSS_GETMIC_HEADER = '\x60\x23\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02' token = self.MIC() # Let's pad the data pad = (4 - (len(data) % 4)) & 0x3 padStr = chr(pad) * pad data += padStr token['SGN_ALG'] = GSS_HMAC if direction == 'init': token['SND_SEQ'] = struct.pack('>L', sequenceNumber) + '\x00'*4 else: token['SND_SEQ'] = struct.pack('>L', sequenceNumber) + '\xff'*4 Ksign = HMAC.new(sessionKey.contents, 'signaturekey\0', MD5).digest() Sgn_Cksum = MD5.new( struct.pack('<L',15) + str(token)[:8] + data).digest() Sgn_Cksum = HMAC.new(Ksign, Sgn_Cksum, MD5).digest() token['SGN_CKSUM'] = Sgn_Cksum[:8] Kseq = HMAC.new(sessionKey.contents, struct.pack('<L',0), MD5).digest() Kseq = HMAC.new(Kseq, token['SGN_CKSUM'], MD5).digest() token['SND_SEQ'] = ARC4.new(Kseq).encrypt(token['SND_SEQ']) finalData = GSS_GETMIC_HEADER + token.getData() return finalData
def decrypt(self, key): if self['HashAlgo'] == ALGORITHMS.CALG_HMAC.value: hashModule = SHA1 else: hashModule = ALGORITHMS_DATA[self['HashAlgo']][1] prf = lambda p, s: HMAC.new(p, s, hashModule).digest() derivedBlob = self.deriveKey(key, self['Salt'], ALGORITHMS_DATA[self['CryptAlgo']][0] + ALGORITHMS_DATA[self['CryptAlgo']][3], count=self['MasterKeyIterationCount'], hashFunction=prf) cryptKey = derivedBlob[:ALGORITHMS_DATA[self['CryptAlgo']][0]] iv = derivedBlob[ALGORITHMS_DATA[self['CryptAlgo']] [0]:][:ALGORITHMS_DATA[self['CryptAlgo']][3]] cipher = ALGORITHMS_DATA[self['CryptAlgo']][1].new( cryptKey, mode=ALGORITHMS_DATA[self['CryptAlgo']][2], iv=iv) cleartext = cipher.decrypt(self['data']) decryptedKey = cleartext[-64:] hmacSalt = cleartext[:16] hmac = cleartext[16:][:ALGORITHMS_DATA[self['HashAlgo']][0]] hmacKey = HMAC.new(key, hmacSalt, hashModule).digest() hmacCalculated = HMAC.new(hmacKey, decryptedKey, hashModule).digest() if hmacCalculated[:ALGORITHMS_DATA[self['HashAlgo']][0]] == hmac: self.decryptedKey = decryptedKey return decryptedKey else: return None
def GSS_GetMIC(self, sessionKey, data, sequenceNumber, direction='init'): GSS_GETMIC_HEADER = '\x60\x23\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02' token = self.MIC() # Let's pad the data pad = (4 - (len(data) % 4)) & 0x3 padStr = chr(pad) * pad data += padStr token['SGN_ALG'] = GSS_HMAC if direction == 'init': token['SND_SEQ'] = struct.pack('>L', sequenceNumber) + '\x00' * 4 else: token['SND_SEQ'] = struct.pack('>L', sequenceNumber) + '\xff' * 4 Ksign = HMAC.new(sessionKey.contents, 'signaturekey\0', MD5).digest() Sgn_Cksum = MD5.new(struct.pack('<L', 15) + str(token)[:8] + data).digest() Sgn_Cksum = HMAC.new(Ksign, Sgn_Cksum, MD5).digest() token['SGN_CKSUM'] = Sgn_Cksum[:8] Kseq = HMAC.new(sessionKey.contents, struct.pack('<L', 0), MD5).digest() Kseq = HMAC.new(Kseq, token['SGN_CKSUM'], MD5).digest() token['SND_SEQ'] = ARC4.new(Kseq).encrypt(token['SND_SEQ']) finalData = GSS_GETMIC_HEADER + token.getData() return finalData
def decrypt(self, key): if self['HashAlgo'] == ALGORITHMS.CALG_HMAC.value: hashModule = SHA1 else: hashModule = ALGORITHMS_DATA[self['HashAlgo']][1] prf = lambda p, s: HMAC.new(p, s, hashModule).digest() derivedBlob = self.deriveKey(key, self['Salt'], ALGORITHMS_DATA[self['CryptAlgo']][0] + ALGORITHMS_DATA[self['CryptAlgo']][3], count=self['MasterKeyIterationCount'], hashFunction=prf) cryptKey = derivedBlob[:ALGORITHMS_DATA[self['CryptAlgo']][0]] iv = derivedBlob[ALGORITHMS_DATA[self['CryptAlgo']][0]:][:ALGORITHMS_DATA[self['CryptAlgo']][3]] cipher = ALGORITHMS_DATA[self['CryptAlgo']][1].new(cryptKey, mode = ALGORITHMS_DATA[self['CryptAlgo']][2], iv = iv) cleartext = cipher.decrypt(self['data']) decryptedKey = cleartext[-64:] hmacSalt = cleartext[:16] hmac = cleartext[16:][:ALGORITHMS_DATA[self['HashAlgo']][0]] hmacKey = HMAC.new(key, hmacSalt, hashModule).digest() hmacCalculated = HMAC.new(hmacKey, decryptedKey, hashModule ).digest() if hmacCalculated[:ALGORITHMS_DATA[self['HashAlgo']][0]] == hmac: self.decryptedKey = decryptedKey return decryptedKey else: return None
def encrypt(cls, key, keyusage, plaintext, confounder): if confounder is None: confounder = get_random_bytes(8) ki = HMAC.new(key.contents, cls.usage_str(keyusage), MD5).digest() cksum = HMAC.new(ki, confounder + plaintext, MD5).digest() ke = HMAC.new(ki, cksum, MD5).digest() return cksum + ARC4.new(ke).encrypt(bytes(confounder + plaintext))
def ComputeResponsev2(NegFlg, ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChallenge, Time=None, ServerName=None, av_pairs=None): if Time is None: Time = nttime.NtTime(nttime.datetime.now()) if ServerName is None: ServerName = "SERVER" ServerName = ServerName.encode("utf-16-le") TimeBuf = array.array("B") cur = core.Cursor(TimeBuf, 0) cur.encode_uint64le(Time) Responseversion = "\x01" HiResponseversion = "\x01" ntlmv2_client_challenge = NTLMv2ClientChallenge() ntlmv2_client_challenge.time_stamp = Time ntlmv2_client_challenge.challenge_from_client = ClientChallenge if av_pairs is not None: ntlmv2_client_challenge.av_pairs = av_pairs temp = encode_frame(ntlmv2_client_challenge).tostring() NTProofStr = HMAC.new(ResponseKeyNT, ServerChallenge + temp, MD5).digest() NtChallengeResponse = NTProofStr + temp LmChallengeResponse = HMAC.new(ResponseKeyLM, ServerChallenge + ClientChallenge, MD5).digest() +\ ClientChallenge SessionBaseKey = HMAC.new(ResponseKeyNT, NTProofStr, MD5).digest() return NtChallengeResponse, LmChallengeResponse, SessionBaseKey
def deriveKeysFromUser(self, sid, password): # Will generate two keys, one with SHA1 and another with MD4 key1 = HMAC.new( SHA1.new(password.encode('utf-16le')).digest(), (sid + '\0').encode('utf-16le'), SHA1).digest() key2 = HMAC.new( MD4.new(password.encode('utf-16le')).digest(), (sid + '\0').encode('utf-16le'), SHA1).digest() return key1, key2
def deriveKeysFromUser(self, sid, password): # Will generate two keys, one with SHA1 and another with MD4 key1 = HMAC.new(SHA1.new(password.encode('utf-16le')).digest(), (sid + '\0').encode('utf-16le'), SHA1).digest() key2 = HMAC.new(MD4.new(password.encode('utf-16le')).digest(), (sid + '\0').encode('utf-16le'), SHA1).digest() # For Protected users tmpKey = pbkdf2_hmac('sha256', MD4.new(password.encode('utf-16le')).digest(), sid.encode('utf-16le'), 10000) tmpKey2 = pbkdf2_hmac('sha256', tmpKey, sid.encode('utf-16le'), 1)[:16] key3 = HMAC.new(tmpKey2, (sid + '\0').encode('utf-16le'), SHA1).digest()[:20] return key1, key2, key3
def decrypt(self, key, entropy=None): keyHash = SHA1.new(key).digest() sessionKey = HMAC.new(keyHash, self['Salt'], ALGORITHMS_DATA[self['HashAlgo']][1]) if entropy is not None: sessionKey.update(entropy) sessionKey = sessionKey.digest() # Derive the key derivedKey = self.deriveKey(sessionKey) cipher = ALGORITHMS_DATA[self['CryptAlgo']][1].new( derivedKey[:ALGORITHMS_DATA[self['CryptAlgo']][0]], mode=ALGORITHMS_DATA[self['CryptAlgo']][2], iv=b'\x00' * ALGORITHMS_DATA[self['CryptAlgo']][3]) cleartext = unpad(cipher.decrypt(self['Data']), ALGORITHMS_DATA[self['CryptAlgo']][1].block_size) # Now check the signature # ToDo Fix this, it's just ugly, more testing so we can remove one toSign = (self.rawData[20:][:len(self.rawData) - 20 - len(self['Sign']) - 4]) # Calculate the different HMACKeys keyHash2 = keyHash + b"\x00" * ALGORITHMS_DATA[ self['HashAlgo']][1].block_size ipad = bytearray([i ^ 0x36 for i in bytearray(keyHash2) ][:ALGORITHMS_DATA[self['HashAlgo']][1].block_size]) opad = bytearray([i ^ 0x5c for i in bytearray(keyHash2) ][:ALGORITHMS_DATA[self['HashAlgo']][1].block_size]) a = ALGORITHMS_DATA[self['HashAlgo']][1].new(ipad) a.update(self['HMac']) hmacCalculated1 = ALGORITHMS_DATA[self['HashAlgo']][1].new(opad) hmacCalculated1.update(a.digest()) if entropy is not None: hmacCalculated1.update(entropy) hmacCalculated1.update(toSign) hmacCalculated3 = HMAC.new(keyHash, self['HMac'], ALGORITHMS_DATA[self['HashAlgo']][1]) if entropy is not None: hmacCalculated3.update(entropy) hmacCalculated3.update(toSign) if hmacCalculated1.digest() == self['Sign'] or hmacCalculated3.digest( ) == self['Sign']: return cleartext else: return None
def runTest(self): key = b("\x90\x91\x92\x93") * 4 payload = b("\x00") * 100 for hashname, hashmod in self.hashmods.items(): if hashmod is None: continue self.description = "Test HMAC in combination with " + hashname one = HMAC.new(key, payload, hashmod).digest() two = HMAC.new(key, payload, hashmod.new()).digest() self.assertEqual(one, two)
def generate_msl_request_data(self, data): """ generate_msl_request_data() @param data: Data to wrap in encryption envelopes so it can be sent to MSL API @return: Chunked payload and header of data """ header = self.header.copy() header['userauthdata'] = self.msl_session['user_auth_data'] header_envelope = pymsl.utils.msl_encrypt( self.msl_session, pymsl.utils.dumps(header) ) header_signature = HMAC.new( self.msl_session['session_keys']['sign_key'], header_envelope, SHA256 ).digest() enc_header = { 'headerdata': base64.b64encode(header_envelope).decode('utf8'), 'signature': base64.b64encode(header_signature).decode('utf8'), 'mastertoken': self.msl_session['session_keys']['mastertoken'], } payload = { 'messageid': self.msl_session['message_id'], 'data': base64.b64encode( pymsl.utils.dumps(data).encode('utf8') ).decode('utf8'), 'sequencenumber': 1, 'endofmsg': True } payload_envelope = pymsl.utils.msl_encrypt( self.msl_session, pymsl.utils.dumps(payload) ) payload_signature = HMAC.new( self.msl_session['session_keys']['sign_key'], payload_envelope, SHA256 ).digest() payload_chunk = { 'payload': base64.b64encode(payload_envelope).decode('utf8'), 'signature': base64.b64encode(payload_signature).decode('utf8') } return pymsl.utils.dumps(enc_header) + pymsl.utils.dumps(payload_chunk)
def crack_pwd(self, KA, mac): for pwd, KX in self.pwd_list: sec = (KA * KX) % self.N key = SHA256.new(int_to_bytes(sec)).digest() try: HMAC.new(key, self.salt, SHA256).verify(mac) print('Server: password found', pwd) return pwd except ValueError: pass print('Server: password NOT found') return None
def verfiyMessageSignature(self, message, hex_mac, method=None, slot_id=DEFAULT_KEY): """ verify the hex mac is same for the message - the comparison is done in a constant time comparison :param message: the original message :param hex_mac: the to compared mac in hex :param method: the hash method - we use by default sha256 :param slot_id: which key should be used :return: boolean """ sign_key = None result = True if method is None: method = SHA256 try: sign_key = self.getSecret(slot_id) hmac = HMAC.new(sign_key, message, method) sign_mac = HMAC.new(sign_key, message, method).hexdigest() res = 0 # as we compare on hex, we have to multiply by 2 digest_size = hmac.digest_size * 2 for x, y in zip(hex_mac, sign_mac): res |= ord(x) ^ ord(y) if len(sign_mac) != digest_size: result = False if res: result = False except ValueError as err: log.error("Mac Comparison failed! %r", err) except Exception as exx: pass finally: if sign_key: zerome(sign_key) del sign_key return result
def deriveKeysFromUserkey(self, sid, pwdhash): if len(pwdhash) == 20: # SHA1 key1 = HMAC.new(pwdhash, (sid + '\0').encode('utf-16le'), SHA1).digest() key2 = None else: # Assume MD4 key1 = HMAC.new(pwdhash, (sid + '\0').encode('utf-16le'), SHA1).digest() # For Protected users tmpKey = pbkdf2_hmac('sha256', pwdhash, sid.encode('utf-16le'), 10000) tmpKey2 = pbkdf2_hmac('sha256', tmpKey, sid.encode('utf-16le'), 1)[:16] key2 = HMAC.new(tmpKey2, (sid + '\0').encode('utf-16le'), SHA1).digest()[:20] return key1, key2
def master(master_key, sid, password): #master_key fp = open(master_key, 'rb') data = fp.read() mkf = MasterKeyFile(data) if DEBUG: mkf.dump() fp.close() data = data[len(mkf):] mk = MasterKey(data[:mkf['MasterKeyLen']]) # Will generate two keys, one with SHA1 and another with MD4 key1 = HMAC.new( SHA1.new(password.encode('utf-16le')).digest(), (sid + '\0').encode('utf-16le'), SHA1).digest() key2 = HMAC.new( MD4.new(password.encode('utf-16le')).digest(), (sid + '\0').encode('utf-16le'), SHA1).digest() # For Protected users tmpKey = pbkdf2_hmac('sha256', MD4.new(password.encode('utf-16le')).digest(), sid.encode('utf-16le'), 10000) tmpKey2 = pbkdf2_hmac('sha256', tmpKey, sid.encode('utf-16le'), 1)[:16] key3 = HMAC.new(tmpKey2, (sid + '\0').encode('utf-16le'), SHA1).digest()[:20] #/key1, key2, key3 = self.deriveKeysFromUser(self.options.sid, password) # if mkf['flags'] & 4 ? SHA1 : MD4 decryptedKey = mk.decrypt(key3) if decryptedKey: print('Decrypted key with User Key (MD4 protected)') print('Decrypted key: 0x%s' % hexlify(decryptedKey).decode('latin-1')) return decryptedKey decryptedKey = mk.decrypt(key2) if decryptedKey: print('Decrypted key with User Key (MD4)') print('Decrypted key: 0x%s' % hexlify(decryptedKey).decode('latin-1')) return decryptedKey decryptedKey = mk.decrypt(key1) if decryptedKey: print('Decrypted key with User Key (SHA1)') print('Decrypted key: 0x%s' % hexlify(decryptedKey).decode('latin-1')) return decryptedKey
def signMessage(self, message, method=None, slot_id=DEFAULT_KEY): """ create the hex mac for the message - :param message: the original message :param method: the hash method - we use by default sha256 :param slot_id: which key should be used :return: hex mac """ sign_key = None if method is None: method = SHA256 try: sign_key = self.getSecret(slot_id) hex_mac = HMAC.new(sign_key, message, method).hexdigest() finally: if sign_key: zerome(sign_key) del sign_key return hex_mac
def encrypt(plaintext): iv = urandom(16) salt = urandom(8) iterations = 1000 ks = 128 ts = 64 hash_func = lambda k, s: HMAC.new(k, s, SHA256).digest() password = b64encode(urandom(32)) key = PBKDF2(password, salt=salt, count=iterations, prf=hash_func) smalliv = trunc_iv(iv, plaintext, 0) cipher = AES.new(key, mode=AES.MODE_CCM, nonce=smalliv, mac_len=ts // 8) ciphertext = b''.join(cipher.encrypt_and_digest(plaintext)) # OrderedDict because 0bin is a piece of shit requiring "iv" as the first key return password.decode('ascii'), OrderedDict([ ('iv', b64encode(iv).decode('ascii')), ('v', 1), ('iter', iterations), ('ks', ks), ('ts', ts), ('mode', 'ccm'), ('adata', ''), ('cipher', 'aes'), ('salt', b64encode(salt).decode('ascii')), ('ct', b64encode(ciphertext).decode('ascii')), ])
def decrypt(secretkey, params): iv = b64decode(params['iv']) salt = b64decode(params['salt']) #~ keylen = params.get('ks', 128) // 8 # FIXME use somewhere? taglen = params.get('ts', 64) // 8 iterations = params.get('iter', 1000) data = b64decode(params['ct']) ciphertext = data[:-taglen] tag = data[-taglen:] if params.get('adata'): raise NotImplementedError('authenticated data support is not implemented') iv = trunc_iv(iv, ciphertext, taglen) hash_func = lambda k, s: HMAC.new(k, s, SHA256).digest() key = PBKDF2(secretkey, salt=salt, count=iterations, prf=hash_func) mode_str = params.get('mode', 'ccm') mode = dict(ccm=AES.MODE_CCM)[mode_str] if mode_str == 'ccm': cipher = AES.new(key, mode=AES.MODE_CCM, nonce=iv, mac_len=taglen) else: cipher = AES.new(key, mode=mode, iv=iv) decrypted = cipher.decrypt_and_verify(ciphertext, tag) return decrypted
def __init__(self, key, data): if isinstance(key, str): key = key.encode() if isinstance(data, str): data = data.encode() self.hmac = HMAC.new(key, digestmod=SHA256) self.hmac.update(data)
def deriveKey(self, sessionKey): def fixparity(deskey): from six import indexbytes, b temp = b'' for i in range(len(deskey)): t = (bin(indexbytes(deskey,i))[2:]).rjust(8,'0') if t[:7].count('1') %2 == 0: temp+= b(chr(int(t[:7]+'1',2))) else: temp+= b(chr(int(t[:7]+'0',2))) return temp if len(sessionKey) > ALGORITHMS_DATA[self['HashAlgo']][4]: derivedKey = HMAC.new(sessionKey, digestmod = ALGORITHMS_DATA[self['HashAlgo']][1]).digest() else: derivedKey = sessionKey if len(derivedKey) < ALGORITHMS_DATA[self['CryptAlgo']][0]: # Extend the key derivedKey += b'\x00'*ALGORITHMS_DATA[self['HashAlgo']][4] ipad = bytearray([ i ^ 0x36 for i in bytearray(derivedKey)][:ALGORITHMS_DATA[self['HashAlgo']][4]]) opad = bytearray([ i ^ 0x5c for i in bytearray(derivedKey)][:ALGORITHMS_DATA[self['HashAlgo']][4]]) derivedKey = ALGORITHMS_DATA[self['HashAlgo']][1].new(ipad).digest() + \ ALGORITHMS_DATA[self['HashAlgo']][1].new(opad).digest() derivedKey = fixparity(derivedKey) return derivedKey
def test_hmac_used_matches_selected_ciphersuite(self): import struct # RSA_WITH_3DES_EDE_CBC_SHA cipher_suite = 0xa plaintext = "a" * 32 sec_params = tlsc.TLSSecurityParameters.from_pre_master_secret(self.prf, cipher_suite, self.pre_master_secret, self.client_random, self.server_random) tls_ctx = tlsc.TLSSessionCtx() tls_ctx.negotiated.version = tls.TLSVersion.TLS_1_0 tls_ctx.sec_params = sec_params tls_ctx.client_ctx.sym_keystore = sec_params.client_keystore self.assertEqual(sec_params.master_secret, self.master_secret) crypto_ctx = tlsc.CBCCryptoContext(tls_ctx, tls_ctx.client_ctx) # Pycryptodome does not expose the mode attribute # self.assertEqual(client_enc_cipher.mode, DES3.MODE_CBC) crypto_data = tlsc.CryptoData.from_context(tls_ctx, tls_ctx.client_ctx, plaintext) crypto_container = tlsc.CBCCryptoContainer.from_context(tls_ctx, tls_ctx.client_ctx, crypto_data) sequence_ = struct.pack("!Q", crypto_data.sequence) content_type_ = struct.pack("!B", crypto_data.content_type) version_ = struct.pack("!H", crypto_data.version) len_ = struct.pack("!H", crypto_data.data_len) digest_input = "%s%s%s%s%s" % (sequence_, content_type_, version_, len_, plaintext) self.assertEqual(crypto_container.mac, HMAC.new(sec_params.client_keystore.hmac, digest_input, digestmod=SHA).digest()) decrypted = crypto_ctx.decrypt(crypto_ctx.encrypt(crypto_container)) self.assertEqual(str(crypto_container), decrypted) self.assertTrue(str(crypto_container).startswith(plaintext))
def NTOWFv2(password, user, userdom): nt_passwd = password.encode("utf-16-le") nt_hash_passwd = MD4.new(nt_passwd).digest() nt_userdom = (user.upper() + userdom).encode("utf-16-le") return HMAC.new(nt_hash_passwd, nt_userdom, MD5).digest()
def _pbkdf2(password, salt, n_bytes, count): # the form of the prf below is taken from the code for PBKDF2 return PBKDF2(password, salt, dkLen=n_bytes, count=count, prf=lambda p, s: HMAC.new(p, s, HASH).digest())
def build_table(RAM2, keywords): """ This function builds our table which allows us to find the location of the first pointer in the chain for a given word. The scheme I've been building uses an FKS table here but looking online, that seemed really complicated. Dictionaries have been used in other schemes (see my report) so I chose to use that here. """ table = {} for entry in RAM2: # If this is the first element in a word chain: if entry[-1]: # The location in RAM2 is the same as RAM3 but can be searched easily index = RAM2.index(entry) # Again, we use HMAC as a PRF to derive key_w PRF = HMAC.new(key_f, digestmod=SHA256) PRF.update(pkcs7_pad(keywords[entry[2]].encode())) key_w = PRF.digest() # Encrypt the index where the chain starts. This way the server #can know nothing about where a given chain starts until we search #for that word. cipher = AES.new(key_w, AES.MODE_CBC, iv) value = cipher.encrypt(pkcs7_pad(str(index).encode())) # If I was implementing the scheme correctly this would be a small #domain PRP and table would be an FKS table. But a dictionary #should work just fine. PRP = AES.new(key_p, AES.MODE_CBC, iv) table_location = PRP.encrypt(pkcs7_pad( keywords[entry[2]].encode())) table[table_location] = value return table
def build_RAM3(RAM2, keywords): """ This function encrypts everything in RAM2. It does this by first finding key_w = PRF(key_f, word) for whatever word the current list is tracking. It then uses that AES with key_w to encrypt the two elements in RAM2 (there is no longer any need to keep track of the word so we can ditch the third element, and the boolean is only being used for the build_table() function). """ RAM3 = [] table = build_table(RAM2, keywords) for element in RAM2: current_list = [] # Here we find key_w which is our word run through a PRF PRF = HMAC.new(key_f, digestmod=SHA256) PRF.update(pkcs7_pad(keywords[element[2]].encode())) key_w = PRF.digest() for item in element[:2]: padded_item = pkcs7_pad(str(item).encode()) # I create a new cipher each time because I was having trouble #getting it to work when I didn't. Not sure what the problem was #but this doesn't appear to noticably slow the performance. # There's no need to initialize it again until a new key_w is #selected. cipher = AES.new(key_w, AES.MODE_CBC, iv) ciphertext = cipher.encrypt(padded_item) current_list.append(ciphertext) # current_list is now [enc(documentID), enc(pointer to next elt)] # using a key derived by running the word through a PRF (HMAC) RAM3.append(current_list) return RAM3, table
def decrypt(secretkey, params): iv = b64decode(params['iv']) salt = b64decode(params['salt']) #~ keylen = params.get('ks', 128) // 8 # FIXME use somewhere? taglen = params.get('ts', 64) // 8 iterations = params.get('iter', 1000) data = b64decode(params['ct']) ciphertext = data[:-taglen] tag = data[-taglen:] if params.get('adata'): raise NotImplementedError( 'authenticated data support is not implemented') iv = trunc_iv(iv, ciphertext, taglen) hash_func = lambda k, s: HMAC.new(k, s, SHA256).digest() key = PBKDF2(secretkey, salt=salt, count=iterations, prf=hash_func) mode_str = params.get('mode', 'ccm') mode = dict(ccm=AES.MODE_CCM)[mode_str] if mode_str == 'ccm': cipher = AES.new(key, mode=AES.MODE_CCM, nonce=iv, mac_len=taglen) else: cipher = AES.new(key, mode=mode, iv=iv) decrypted = cipher.decrypt_and_verify(ciphertext, tag) return decrypted
def aes_cbc_hmac_decrypt(key, iv, aad, ct, tag): """ Perform authenticated decryption with the combined AES-CBC and HMAC algorithm. :param key : Key; length MUST be 32, 48, or 64 octets :param iv : Initialization vector; length MUST be 16 octets :param aad: Additional authenticated data :param ct : Cipher text :param tag: Authentication tag :return: (plaintext, result) tuple, with plaintext as bytes and result as boolean """ ka, ke, seclen, dgst = get_keys_seclen_dgst(key, iv) # Verify A || IV || E || AL al = pack("!Q", 8*len(aad)) if isinstance(aad, str): aad = aad.encode("utf-8") mac_input = aad + iv + ct + al h = HMAC.new(ka, digestmod=dgst) h.update(mac_input) candidate = h.digest()[:seclen] # Decrypt if verified if candidate == tag: cipher = AES.new(ke, AES.MODE_CBC, iv) pt = pkcs5trim(cipher.decrypt(ct)) return pt else: raise VerificationFailure('AES-CBC HMAC')
def aes_cbc_hmac_encrypt(key, iv, aad, pt): """ Perform authenticated encryption with the combined AES-CBC and HMAC algorithm. :param key: key; length MUST be 32, 48, or 64 octets :param iv: Initialization vector; length MUST be 16 octets :param aad: Additional authenticated data :param pt: Plaintext :return: (ciphertext, tag) tuple, with each as bytes """ ka, ke, seclen, dgst = get_keys_seclen_dgst(key, iv) # Encrypt cipher = AES.new(ke, AES.MODE_CBC, iv) ct = cipher.encrypt(pkcs5pad(pt)) # MAC A || IV || E || AL al = pack("!Q", 8*len(aad)) mac_input = aad + iv + ct + al h = HMAC.new(ka, digestmod=dgst) h.update(mac_input) tag = h.digest()[:seclen] return ct, tag
def entropy_to_privkey(entropy: bytes) -> bytes: priv_key = PBKDF2(entropy, entropy, dkLen=32, count=PBKDF_ITERATIONS, prf=lambda p, s: HMAC.new(p, s, SHA256).digest()) return priv_key
def initiate_session(self): ''' Perform the initial connection handshake for agreeing on a shared secret. This can be broken into code run just on the server or just on the client. All the function want to do here is to ensure the data confidentiality. Key: A key used to generate IV. Obtained from shuffled shared hash. ''' if self.server or self.client: # DH crete keys my_public_key, my_private_key = create_dh_key() # Send them our public key self.send(bytes(str(my_public_key), "ascii")) # Receive their public key their_public_key = int(self.recv()) # Obtain our shared secret self.shared_hash = calculate_dh_secret(their_public_key, my_private_key) print("Shared hash: {}".format(self.shared_hash)) key = list(self.shared_hash) random.shuffle(key) # Generate IV iv = bytes(str(key).encode()[:AES.block_size]) # Convert hexstr to byte self.shared_hash = bytes.fromhex(self.shared_hash) # AES encrypt with CFB mode self.cipher = AES.new(self.shared_hash, AES.MODE_CFB, iv) self.hmac = HMAC.new(self.shared_hash, None, SHA256.new())
def test2(self): """From draft-josefsson-scrypt-kdf-01, Chapter 10""" output_1 = t2b(""" 55 ac 04 6e 56 e3 08 9f ec 16 91 c2 25 44 b6 05 f9 41 85 21 6d de 04 65 e6 8b 9d 57 c2 0d ac bc 49 ca 9c cc f1 79 b6 45 99 16 64 b3 9d 77 ef 31 7c 71 b8 45 b1 e3 0b d5 09 11 20 41 d3 a1 97 83 """) output_2 = t2b(""" 4d dc d8 f6 0b 98 be 21 83 0c ee 5e f2 27 01 f9 64 1a 44 18 d0 4c 04 14 ae ff 08 87 6b 34 ab 56 a1 d4 25 a1 22 58 33 54 9a db 84 1b 51 c9 b3 17 6a 27 2b de bb a1 d0 78 47 8f 62 b3 97 f3 3c 8d """) prf_hmac_sha256 = lambda p, s: HMAC.new(p, s, SHA256).digest() output = PBKDF2(b("passwd"), b("salt"), 64, 1, prf=prf_hmac_sha256) self.assertEqual(output, output_1) output = PBKDF2(b("Password"), b("NaCl"), 64, 80000, prf=prf_hmac_sha256) self.assertEqual(output, output_2)
def __decryptHash(self, key, value, iv): hmac_md5 = HMAC.new(key, iv) rc4key = hmac_md5.digest() rc4 = ARC4.new(rc4key) data = rc4.encrypt(value) return data
def deriveKey(self, sessionKey): def fixparity(deskey): from six import indexbytes, b temp = b'' for i in range(len(deskey)): t = (bin(indexbytes(deskey, i))[2:]).rjust(8, '0') if t[:7].count('1') % 2 == 0: temp += b(chr(int(t[:7] + '1', 2))) else: temp += b(chr(int(t[:7] + '0', 2))) return temp if len(sessionKey) > ALGORITHMS_DATA[self['HashAlgo']][4]: derivedKey = HMAC.new( sessionKey, digestmod=ALGORITHMS_DATA[self['HashAlgo']][1]).digest() else: derivedKey = sessionKey if len(derivedKey) < ALGORITHMS_DATA[self['CryptAlgo']][0]: # Extend the key derivedKey += b'\x00' * ALGORITHMS_DATA[self['HashAlgo']][4] ipad = bytearray([i ^ 0x36 for i in bytearray(derivedKey) ][:ALGORITHMS_DATA[self['HashAlgo']][4]]) opad = bytearray([i ^ 0x5c for i in bytearray(derivedKey) ][:ALGORITHMS_DATA[self['HashAlgo']][4]]) derivedKey = ALGORITHMS_DATA[self['HashAlgo']][1].new(ipad).digest() + \ ALGORITHMS_DATA[self['HashAlgo']][1].new(opad).digest() derivedKey = fixparity(derivedKey) return derivedKey
def encrypt(cls, key, keyusage, plaintext, confounder): ki = cls.derive(key, pack('>IB', keyusage, 0x55)) ke = cls.derive(key, pack('>IB', keyusage, 0xAA)) if confounder is None: confounder = get_random_bytes(cls.blocksize) basic_plaintext = confounder + _zeropad(plaintext, cls.padsize) hmac = HMAC.new(ki.contents, basic_plaintext, cls.hashmod).digest() return cls.basic_encrypt(ke, basic_plaintext) + hmac[:cls.macsize]
def decrypt(self, key, entropy = None): keyHash = SHA1.new(key).digest() sessionKey = HMAC.new(keyHash, self['Salt'], ALGORITHMS_DATA[self['HashAlgo']][1]) if entropy is not None: sessionKey.update(entropy) sessionKey = sessionKey.digest() # Derive the key derivedKey = self.deriveKey(sessionKey) cipher = ALGORITHMS_DATA[self['CryptAlgo']][1].new(derivedKey[:ALGORITHMS_DATA[self['CryptAlgo']][0]], mode=ALGORITHMS_DATA[self['CryptAlgo']][2], iv=b'\x00'*ALGORITHMS_DATA[self['CryptAlgo']][3]) cleartext = unpad(cipher.decrypt(self['Data']), ALGORITHMS_DATA[self['CryptAlgo']][1].block_size) # Now check the signature # ToDo Fix this, it's just ugly, more testing so we can remove one toSign = (self.rawData[20:][:len(self.rawData)-20-len(self['Sign'])-4]) # Calculate the different HMACKeys keyHash2 = keyHash + b"\x00"*ALGORITHMS_DATA[self['HashAlgo']][1].block_size ipad = bytearray([i ^ 0x36 for i in bytearray(keyHash2)][:ALGORITHMS_DATA[self['HashAlgo']][1].block_size]) opad = bytearray([i ^ 0x5c for i in bytearray(keyHash2)][:ALGORITHMS_DATA[self['HashAlgo']][1].block_size]) a = ALGORITHMS_DATA[self['HashAlgo']][1].new(ipad) a.update(self['HMac']) hmacCalculated1 = ALGORITHMS_DATA[self['HashAlgo']][1].new(opad) hmacCalculated1.update(a.digest()) if entropy is not None: hmacCalculated1.update(entropy) hmacCalculated1.update(toSign) hmacCalculated3 = HMAC.new(keyHash, self['HMac'], ALGORITHMS_DATA[self['HashAlgo']][1]) if entropy is not None: hmacCalculated3.update(entropy) hmacCalculated3.update(toSign) if hmacCalculated1.digest() == self['Sign'] or hmacCalculated3.digest() == self['Sign']: return cleartext else: return None
def decrypt(cls, key, keyusage, ciphertext): if len(ciphertext) < 24: raise ValueError('ciphertext too short') cksum, basic_ctext = bytearray(ciphertext[:16]), bytearray(ciphertext[16:]) ki = HMAC.new(key.contents, cls.usage_str(keyusage), MD5).digest() ke = HMAC.new(ki, cksum, MD5).digest() basic_plaintext = bytearray(ARC4.new(ke).decrypt(bytes(basic_ctext))) exp_cksum = bytearray(HMAC.new(ki, basic_plaintext, MD5).digest()) ok = _mac_equal(cksum, exp_cksum) if not ok and keyusage == 9: # Try again with usage 8, due to RFC 4757 errata. ki = HMAC.new(key.contents, pack('<I', 8), MD5).digest() exp_cksum = HMAC.new(ki, basic_plaintext, MD5).digest() ok = _mac_equal(cksum, exp_cksum) if not ok: raise InvalidChecksum('ciphertext integrity failure') # Discard the confounder. return bytes(basic_plaintext[8:])
def test3(self): # Verify that hmac_hash_module works like prf password = b("xxx") salt = b("yyy") for hashmod in (MD5, SHA1, SHA224, SHA256, SHA384, SHA512): pr1 = PBKDF2(password, salt, 16, 100, prf=lambda p, s: HMAC.new(p,s,hashmod).digest()) pr2 = PBKDF2(password, salt, 16, 100, hmac_hash_module=hashmod) self.assertEqual(pr1, pr2)
def _compute_nonce(self, mhash): """Generate k in a deterministic way""" # See section 3.2 in RFC6979.txt # Step a h1 = mhash.digest() # Step b mask_v = bchr(1) * mhash.digest_size # Step c nonce_k = bchr(0) * mhash.digest_size for int_oct in 0, 1: # Step d/f nonce_k = HMAC.new(nonce_k, mask_v + bchr(int_oct) + self._int2octets(self._private_key) + self._bits2octets(h1), mhash).digest() # Step e/g mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() nonce = -1 while not (0 < nonce < self._order): # Step h.C (second part) if nonce != -1: nonce_k = HMAC.new(nonce_k, mask_v + bchr(0), mhash).digest() mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() # Step h.A mask_t = b("") # Step h.B while len(mask_t) < self._order_bytes: mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() mask_t += mask_v # Step h.C (first part) nonce = self._bits2int(mask_t) return nonce
def loads(cls, data, store_password, try_decrypt_keys=True): """ See :meth:`jks.jks.KeyStore.loads`. :param bytes data: Byte string representation of the keystore to be loaded. :param str password: Keystore password string :param bool try_decrypt_keys: Whether to automatically try to decrypt any encountered key entries using the same password as the keystore password. :returns: A loaded :class:`BksKeyStore` instance, if the keystore could be successfully parsed and the supplied store password is correct. If the ``try_decrypt_keys`` parameters was set to ``True``, any keys that could be successfully decrypted using the store password have already been decrypted; otherwise, no atttempt to decrypt any key entries is made. :raises BadKeystoreFormatException: If the keystore is malformed in some way :raises UnsupportedKeystoreVersionException: If the keystore contains an unknown format version number :raises KeystoreSignatureException: If the keystore signature could not be verified using the supplied store password :raises DuplicateAliasException: If the keystore contains duplicate aliases """ try: pos = 0 version = b4.unpack_from(data, pos)[0]; pos += 4 if version not in [1,2]: raise UnsupportedKeystoreVersionException("Unsupported BKS keystore version; only V1 and V2 supported, found v"+repr(version)) salt, pos = cls._read_data(data, pos) iteration_count = b4.unpack_from(data, pos)[0]; pos += 4 store_type = "bks" entries, size = cls._load_bks_entries(data[pos:], store_type, store_password, try_decrypt_keys=try_decrypt_keys) hmac_fn = hashlib.sha1 hmac_digest_size = hmac_fn().digest_size hmac_key_size = hmac_digest_size*8 if version != 1 else hmac_digest_size hmac_key = rfc7292.derive_key(hmac_fn, rfc7292.PURPOSE_MAC_MATERIAL, store_password, salt, iteration_count, hmac_key_size//8) store_data = data[pos:pos+size] store_hmac = data[pos+size:pos+size+hmac_digest_size] if len(store_hmac) != hmac_digest_size: raise BadKeystoreFormatException("Bad HMAC size; found %d bytes, expected %d bytes" % (len(store_hmac), hmac_digest_size)) hmac = HMAC.new(hmac_key, digestmod=SHA) hmac.update(store_data) computed_hmac = hmac.digest() if store_hmac != computed_hmac: raise KeystoreSignatureException("Hash mismatch; incorrect keystore password?") return cls(store_type, entries, version=version) except struct.error as e: raise BadKeystoreFormatException(e)
def decrypt(cls, key, keyusage, ciphertext): ki = cls.derive(key, pack('>IB', keyusage, 0x55)) ke = cls.derive(key, pack('>IB', keyusage, 0xAA)) if len(ciphertext) < cls.blocksize + cls.macsize: raise ValueError('ciphertext too short') basic_ctext, mac = bytearray(ciphertext[:-cls.macsize]), bytearray(ciphertext[-cls.macsize:]) if len(basic_ctext) % cls.padsize != 0: raise ValueError('ciphertext does not meet padding requirement') basic_plaintext = cls.basic_decrypt(ke, bytes(basic_ctext)) hmac = bytearray(HMAC.new(ki.contents, basic_plaintext, cls.hashmod).digest()) expmac = hmac[:cls.macsize] if not _mac_equal(mac, expmac): raise InvalidChecksum('ciphertext integrity failure') # Discard the confounder. return bytes(basic_plaintext[cls.blocksize:])
def KXKEY(NegFlg, SessionBaseKey, LmChallengeResponse, ServerChallenge, ResponseKeyLM): if NegFlg & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: hm = HMAC.new(SessionBaseKey, ServerChallenge +\ LmChallengeResponse[:8], MD5) KeyExchangeKey = hm.digest() else: LMOWF = ResponseKeyLM if NegFlg & NTLMSSP_NEGOTIATE_LMKEY: data = LmChallengeResponse[:8] KeyExchangeKey = DES(LMOWF[:7], data) + \ DES(LMOWF[8] + "\xbd"*6, data) else: if NegFlg & NTLMSSP_REQUEST_NON_NT_SESSION_KEY: KeyExchangeKey = LMOWF[:8] + "\0"*8 else: KeyExchangeKey = SessionBaseKey return KeyExchangeKey
def PBKDF2(password, salt, dkLen=16, count=1000, prf=None): """Derive one or more keys from a password (or passphrase). This function performs key derivation according to the PKCS#5 standard (v2.0), by means of the ``PBKDF2`` algorithm. :Parameters: password : string The secret password or pass phrase to generate the key from. salt : string A string to use for better protection from dictionary attacks. This value does not need to be kept secret, but it should be randomly chosen for each derivation. It is recommended to be at least 8 bytes long. dkLen : integer The cumulative length of the desired keys. Default is 16 bytes, suitable for instance for `Cryptodome.Cipher.AES`. count : integer The number of iterations to carry out. It's recommended to use at least 1000. prf : callable A pseudorandom function. It must be a function that returns a pseudorandom string from two parameters: a secret and a salt. If not specified, HMAC-SHA1 is used. :Return: A byte string of length `dkLen` that can be used as key material. If you wanted multiple keys, just break up this string into segments of the desired length. """ password = tobytes(password) if prf is None: prf = lambda p,s: HMAC.new(p,s,SHA1).digest() def link(s): s[0], s[1] = s[1], prf(password, s[1]) return s[0] key = b('') i = 1 while len(key)<dkLen: s = [ prf(password, salt + struct.pack(">I", i)) ] * 2 key += reduce(strxor, (link(s) for j in range(count)) ) i += 1 return key[:dkLen]
def prf_SHA256(p,s): return HMAC.new(p,s,SHA256).digest()
def prf_SHA1(p,s): return HMAC.new(p,s,SHA1).digest()
def checksum(cls, key, keyusage, text): kc = cls.enc.derive(key, pack('>IB', keyusage, 0x99)) hmac = HMAC.new(kc.contents, text, cls.enc.hashmod).digest() return hmac[:cls.macsize]
def checksum(cls, key, keyusage, text): ksign = HMAC.new(key.contents, b'signaturekey\0', MD5).digest() md5hash = MD5.new(_RC4.usage_str(keyusage) + text).digest() return HMAC.new(ksign, md5hash, MD5).digest()