def run_srp_intended(): """ The original SRP protocol from challenge 38. """ # SERVER (x, v) salt = random_bytes(16) x_serv = int.from_bytes(sha256(salt + password).digest(), "little") v = pow(g, x_serv, n) # CLIENT (I, A) a = randbelow(n) A = pow(g, a, n) # SERVER (B, u) b = randbelow(n) B = pow(g, b, n) u = int.from_bytes(random_bytes(16), "little") # CLIENT (x, S, K) x_clnt = int.from_bytes(sha256(salt + password).digest(), "little") S_clnt = pow(B, a + u * x_clnt, n) K_clnt = sha256(S_clnt.to_bytes(ceil(S_clnt.bit_length() / 8), "little")).digest() HMAC_clnt = pbkdf2_hmac("sha256", K_clnt, salt, 100000) # SERVER (S, K) S_serv = pow(A * pow(v, u, n), b, n) K_serv = sha256(S_serv.to_bytes(ceil(S_serv.bit_length() / 8), "little")).digest() HMAC_serv = pbkdf2_hmac("sha256", K_serv, salt, 100000) assert compare_digest(HMAC_clnt, HMAC_serv) print("Client and server digests matched.")
def get_random_cipher(): key = random_bytes(16) if randint(0, 1): return AES.MODE_ECB, AES.new(key, mode=AES.MODE_ECB) return AES.MODE_CBC, AES.new(key, mode=AES.MODE_CBC, iv=random_bytes(16))
def encrypt_random(): string = choice(STRINGS) key = random_bytes(16) iv = random_bytes(16) cipher = AES.new(key, mode=AES.MODE_CBC, iv=iv) return key, iv, cipher.encrypt(pad(string, 16))
def run_srp_mitm(): """ The MITM protocol from challenge 38. Server does not know password, but wants to crack it using A's HMAC-SHA256. """ # SERVER (x, v) salt = random_bytes(16) # CLIENT (I, A) a = randbelow(n) A = pow(g, a, n) # SERVER (B, u) b = randbelow(n) B = pow(g, b, n) u = int.from_bytes(random_bytes(16), "little") # CLIENT (x, S, K) x_clnt = int.from_bytes(sha256(salt + password).digest(), "little") S_clnt = pow(B, a + u * x_clnt, n) K_clnt = sha256(S_clnt.to_bytes(ceil(S_clnt.bit_length() / 8), "little")).digest() HMAC_clnt = pbkdf2_hmac("sha256", K_clnt, salt, 100000) # Server shouldn't have access to the following. del a del x_clnt del S_clnt del K_clnt # ATTACKER (Have: A, b, B, u, salt, HMAC_clnt) # Goal: Recover the password....... with dictionary attack. # wtf is this dictionary = ["a", "b", "c", "let", "cat", "dog", "me", "in", "out"] for num_words in range(1, 5): for perm in permutations(dictionary, r=num_words): cracked_password = "".join(perm).encode() x_mitm = int.from_bytes( sha256(salt + cracked_password).digest(), "little") v = pow(g, x_mitm, n) S_mitm = pow(A * pow(v, u, n), b, n) K_mitm = sha256( S_mitm.to_bytes(ceil(S_mitm.bit_length() / 8), "little")).digest() HMAC_mitm = pbkdf2_hmac("sha256", K_mitm, salt, 100000) if compare_digest(HMAC_mitm, HMAC_clnt): assert password == cracked_password print("Password successfully cracked.") return print("Failed to crack password.") assert False
def _() -> bytes: '使用 os.urandom 产生一个指定长度的字节字符串' nonlocal size collision_count = 0 while (b := random_bytes(size)) in cache: collision_count += 1 if collision_count > max_collisions: warn( f'get_random_bytes has been updated {size=}, {step=}, {max_collisions=}' ) collision_count = 0 size += step cache.clear()
def diffie_hellman_mitm(): message = b"example message~" print(f"DH'ing message: {message}") # Generate A's DH values. a = randbelow(p) A = pow(g, a, p) print("ACTION: A -> M :: Send `p, g, A`") A = p print("ACTION: M -> B :: Send `p, g, p`") # Generate B's DH values. b = randbelow(p) B = pow(g, b, p) print("ACTION: B -> M :: Send `B`") B = p print("ACTION: M -> A :: Send `p`") # Calculate DH shared key. shared_key_a = sha1(pow(B, a, p).to_bytes(1600, "little"))[:16] # Encrypt message with A's key. iv_a = random_bytes(16) cipher = AES.new(shared_key_a, mode=AES.MODE_CBC, iv=iv_a) message_a = cipher.encrypt(message) print(f"ACTION: A -> M :: Send encrypted message: {message_a}") broken_key = sha1((0).to_bytes(1600, "little"))[:16] cipher = AES.new(broken_key, mode=AES.MODE_CBC, iv=iv_a) broken_message_a = cipher.decrypt(message_a) print(f"ACTION: M :: Decrypted A's message: {broken_message_a}") print(f"ACTION: M -> B :: Relay encrypted message: {message_a}") # Calculate DH shared key. shared_key_b = sha1(pow(A, b, p).to_bytes(1600, "little"))[:16] # Decrypt A's message with shared key. cipher = AES.new(shared_key_b, mode=AES.MODE_CBC, iv=iv_a) decrypted_message_a = cipher.decrypt(message_a) print(f"ACTION: B :: Decrypted A's message: {decrypted_message_a}") iv_b = random_bytes(16) cipher = AES.new(shared_key_b, mode=AES.MODE_CBC, iv=iv_b) message_b = cipher.encrypt(decrypted_message_a) print(f"ACTION: B -> M :: Send A's encrypted message back: {message_b}") cipher = AES.new(broken_key, mode=AES.MODE_CBC, iv=iv_b) broken_message_b = cipher.decrypt(message_b) print(f"ACTION: M :: Decrypted B's message: {broken_message_b}") print(f"ACTION: M -> A :: Relay encrypted message: {message_a}") cipher = AES.new(shared_key_a, mode=AES.MODE_CBC, iv=iv_b) decrypted_message_b = cipher.decrypt(message_b) print(f"ACTION: A :: Decrypted B's message: {decrypted_message_b}") assert broken_message_a == broken_message_b == message
def diffie_hellman_mitm(g): # Assume p & g have been sent, acknowledged, and tampered with. message = b"example message~" print(f"DH'ing message: {message} with g = {g}") # Generate A's DH values. a = randbelow(p) A = pow(g, a, p) print("ACTION: A -> B :: Send `A`") # Generate B's DH values. b = randbelow(p) B = pow(g, b, p) print("ACTION: B -> A :: Send `B`") # Calculate DH shared key. shared_key_a = make_aes_key(pow(B, a, p)) # Encrypt message with A's key. iv_a = random_bytes(16) cipher = AES.new(shared_key_a, mode=AES.MODE_CBC, iv=iv_a) message_a = cipher.encrypt(message) print(f"ACTION: A -> M :: Send encrypted message: {message_a}") if g == 1: broken_keys = [make_aes_key(1)] elif g == p: broken_keys = [make_aes_key(0)] elif g == p - 1: broken_keys = [make_aes_key(i) for i in [1, p - 1]] ciphers = [AES.new(key, mode=AES.MODE_CBC, iv=iv_a) for key in broken_keys] broken_messages_a = [c.decrypt(message_a) for c in ciphers] print( f"ACTION: M :: Decrypted A's message: {b' or '.join(broken_messages_a)}" ) print(f"ACTION: M -> B :: Relay encrypted message: {message_a}") # Calculate DH shared key. shared_key_b = sha1(pow(A, b, p).to_bytes(1600, "little"))[:16] # Decrypt A's message with shared key. cipher = AES.new(shared_key_b, mode=AES.MODE_CBC, iv=iv_a) decrypted_message_a = cipher.decrypt(message_a) print(f"ACTION: B :: Decrypted A's message: {decrypted_message_a}") iv_b = random_bytes(16) cipher = AES.new(shared_key_b, mode=AES.MODE_CBC, iv=iv_b) message_b = cipher.encrypt(decrypted_message_a) print(f"ACTION: B -> M :: Send A's encrypted message back: {message_b}") ciphers = [AES.new(key, mode=AES.MODE_CBC, iv=iv_b) for key in broken_keys] broken_messages_b = [c.decrypt(message_b) for c in ciphers] print( f"ACTION: M :: Decrypted B's message: {b' or '.join(broken_messages_b)}" ) print(f"ACTION: M -> A :: Relay encrypted message: {message_a}") cipher = AES.new(shared_key_a, mode=AES.MODE_CBC, iv=iv_b) decrypted_message_b = cipher.decrypt(message_b) print(f"ACTION: A :: Decrypted B's message: {decrypted_message_b}") assert message in broken_messages_a assert message in broken_messages_b
def encrypt(string): key_iv = random_bytes(16) cipher = AES.new(key_iv, mode=AES.MODE_CBC, iv=key_iv) return key_iv, cipher.encrypt(pad(string, 16))
def encrypt_profile(email): key = random_bytes(16) iv = random_bytes(16) cipher = AES.new(key, mode=AES.MODE_CBC, iv=iv) return key, iv, cipher.encrypt(pad(profile_for(email).encode(), 16))
def run_server(): sock = socket.create_server(("127.0.0.1", PORT)) # Agree on N=[NIST Prime], g=2, k=3, I (email), P (password) while True: print("Server: Waiting for client...") conn, _ = sock.accept() print("Server: Client connection accepted.") # Generate salt as random integer # Generate string xH=SHA256(salt|password) # Convert xH to integer x somehow (put 0x on hexdigest) # Generate v=g**x % N # Save everything but x, xH print("Server: Generating salt, x, v") salt = random_bytes(16) xH = sha256(salt + password).digest() x = int.from_bytes(xH, "little") v = pow(g, x, n) del xH, x # Receive I, A=g**a % N (a la Diffie Hellman) print("Server: Receiving A from client") A = int.from_bytes(conn.recv(1600), "little") # Send salt, B=kv + g**b % N print("Server: Sending salt, B to client") b = randbelow(n) B = k * v + pow(g, b, n) conn.send(salt) conn.send(B.to_bytes(1600, "little")) # Compute string uH = SHA256(A|B), u = integer of uH print("Server: Calculating u") uH = sha256((A + B).to_bytes(1600, "little")).digest() u = int.from_bytes(uH, "little") # Generate S = (A * v**u) ** b % N # Generate K = SHA256(S) print("Server: Calculating S, K") S = pow(A * pow(v, u, n), b, n) K = sha256(S.to_bytes(1600, "little")).digest() # Send "OK" if HMAC-SHA256(K, salt) validates print("Server: Receiving HMAC from client") hmac = pbkdf2_hmac("sha256", K, salt, 100000) client_hmac = conn.recv(32) if compare_digest(hmac, client_hmac): print("Server: HMAC validated!") conn.send(b"OK") else: print("Server: HMAC NOT validated :-(") conn.send(b"NOT OK") conn.close()
def get_padding(): return random_bytes(randint(5, 10))
def generate_random_cipher(): key = random_bytes(16) return AES.new(key, mode=AES.MODE_ECB)
def determine_block_size(encrypter): resize_sizes = [] prev_length = len(encrypter(b"A")) for i in range(2, 64): ciphertext = encrypter(b"A" * i) if len(ciphertext) != prev_length: resize_sizes.append(i) prev_length = len(ciphertext) if len(resize_sizes) == 2: return resize_sizes[1] - resize_sizes[0] def pad(bytestring, boundary=16): return bytestring + (b"\x00" * (boundary - len(bytestring) % boundary)) if __name__ == "__main__": cipher = generate_random_cipher() prefix_size = randint(12, 36) prefix = random_bytes(prefix_size) encrypter = lambda text: cipher.encrypt(pad(prefix + text + string) ) # noqa assert determine_block_size(encrypter) == 16 assert determine_prefix_size(encrypter, 16) == prefix_size print(decode_string(encrypter).rstrip(b"\x00").decode())
def set_secret() -> str: secret = b32encode(random_bytes(20)) with open(SECRET_FILE, 'wb') as f: f.write(secret) return secret
def random(self, bytes_len: int = 1) -> Tuple[bytes, str]: rb: bytes = random_bytes(bytes_len) return rb, self.encode(rb)
"VW50aWwgaGVyIHZvaWNlIGdyZXcgc2hyaWxsLg==", "V2hhdCB2b2ljZSBtb3JlIHN3ZWV0IHRoYW4gaGVycw==", "V2hlbiB5b3VuZyBhbmQgYmVhdXRpZnVsLA==", "U2hlIHJvZGUgdG8gaGFycmllcnM/", "VGhpcyBtYW4gaGFkIGtlcHQgYSBzY2hvb2w=", "QW5kIHJvZGUgb3VyIHdpbmdlZCBob3JzZS4=", "VGhpcyBvdGhlciBoaXMgaGVscGVyIGFuZCBmcmllbmQ=", "V2FzIGNvbWluZyBpbnRvIGhpcyBmb3JjZTs=", "SGUgbWlnaHQgaGF2ZSB3b24gZmFtZSBpbiB0aGUgZW5kLA==", "U28gc2Vuc2l0aXZlIGhpcyBuYXR1cmUgc2VlbWVkLA==", "U28gZGFyaW5nIGFuZCBzd2VldCBoaXMgdGhvdWdodC4=", "VGhpcyBvdGhlciBtYW4gSSBoYWQgZHJlYW1lZA==", "QSBkcnVua2VuLCB2YWluLWdsb3Jpb3VzIGxvdXQu", "SGUgaGFkIGRvbmUgbW9zdCBiaXR0ZXIgd3Jvbmc=", "VG8gc29tZSB3aG8gYXJlIG5lYXIgbXkgaGVhcnQs", "WWV0IEkgbnVtYmVyIGhpbSBpbiB0aGUgc29uZzs=", "SGUsIHRvbywgaGFzIHJlc2lnbmVkIGhpcyBwYXJ0", "SW4gdGhlIGNhc3VhbCBjb21lZHk7", "SGUsIHRvbywgaGFzIGJlZW4gY2hhbmdlZCBpbiBoaXMgdHVybiw=", "VHJhbnNmb3JtZWQgdXR0ZXJseTo=", "QSB0ZXJyaWJsZSBiZWF1dHkgaXMgYm9ybi4=", ] plaintexts = [b64decode(s) for s in STRINGS] key = random_bytes(16) nonce = random_bytes(16) ciphertexts = [ctr_crypt(pt, key, nonce) for pt in plaintexts] # Per instructions, attack this manually.
def wrap_string(string): key = random_bytes(16) iv = random_bytes(16) cipher = AES.new(key, mode=AES.MODE_CBC, iv=iv) uinfo = prefix + quote(string).encode() + suffix return key, iv, cipher.encrypt(pad(uinfo, 16))