def test3(self): for keylen, taglen, result in self.tv3: key = bchr(0) * (keylen // 8 - 1) + bchr(taglen) C = b("") for i in range(128): S = bchr(0) * i N = long_to_bytes(3 * i + 1, 12) cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) cipher.update(S) C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest() N = long_to_bytes(3 * i + 2, 12) cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest() N = long_to_bytes(3 * i + 3, 12) cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) cipher.update(S) C += cipher.encrypt() + cipher.digest() N = long_to_bytes(385, 12) cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) cipher.update(C) result2 = cipher.encrypt() + cipher.digest() self.assertEqual(unhexlify(b(result)), result2)
def digest(self): """Return the **binary** (non-printable) MAC of the message that has been authenticated so far. This method does not change the state of the MAC object. You can continue updating the object after calling this function. :Return: A byte string of `digest_size` bytes. It may contain non-ASCII characters, including null bytes. """ if self._mac_tag is not None: return self._mac_tag if self._data_size > self._max_size: raise ValueError("MAC is unsafe for this message") if len(self._cache) == 0 and self._before_last_ct is not None: ## Last block was full pt = strxor(strxor(self._before_last_ct, self._k1), self._last_pt) else: ## Last block is partial (or message length is zero) ext = self._cache + bchr(0x80) +\ bchr(0) * (self.digest_size - len(self._cache) - 1) pt = strxor(strxor(self._last_ct, self._k2), ext) cipher = self._factory.new(self._key, self._factory.MODE_ECB, **self._cipher_params) self._mac_tag = cipher.encrypt(pt) return self._mac_tag
def digest(self): """Return the **binary** (non-printable) MAC tag of the message that has been authenticated so far. :return: The MAC tag, computed over the data processed so far. Binary form. :rtype: byte string """ if self._mac_tag is not None: return self._mac_tag if self._data_size > self._max_size: raise ValueError("MAC is unsafe for this message") if len(self._cache) == 0 and self._before_last_ct is not None: # Last block was full pt = strxor(strxor(self._before_last_ct, self._k1), self._last_pt) else: # Last block is partial (or message length is zero) ext = self._cache + bchr(0x80) +\ bchr(0) * (self.digest_size - len(self._cache) - 1) pt = strxor(strxor(self._last_ct, self._k2), ext) cipher = self._factory.new(self._key, self._factory.MODE_ECB, **self._cipher_params) self._mac_tag = cipher.encrypt(pt) return self._mac_tag
def _export_subjectPublicKeyInfo(self, compress): # See 2.2 in RFC5480 and 2.3.3 in SEC1 # The first byte is: # - 0x02: compressed, only X-coordinate, Y-coordinate is even # - 0x03: compressed, only X-coordinate, Y-coordinate is odd # - 0x04: uncompressed, X-coordinate is followed by Y-coordinate # # PAI is in theory encoded as 0x00. order_bytes = _curve.order.size_in_bytes() if compress: first_byte = 2 + self.pointQ.y.is_odd() public_key = (bchr(first_byte) + self.pointQ.x.to_bytes(order_bytes)) else: public_key = (bchr(4) + self.pointQ.x.to_bytes(order_bytes) + self.pointQ.y.to_bytes(order_bytes)) unrestricted_oid = "1.2.840.10045.2.1" return _create_subject_public_key_info(unrestricted_oid, public_key, DerObjectId(_curve.oid))
def __init__(self, factory, nonce, mac_len, cipher_params): if factory.block_size != 16: raise ValueError("OCB mode is only available for ciphers" " that operate on 128 bits blocks") self.block_size = 16 """The block size of the underlying cipher, in bytes.""" self.nonce = nonce """Nonce used for this session.""" if len(nonce) not in range(1, 16): raise ValueError("Nonce must be at most 15 bytes long") self._mac_len = mac_len if not 8 <= mac_len <= 16: raise ValueError("MAC tag must be between 8 and 16 bytes long") # Cache for MAC tag self._mac_tag = None # Cache for unaligned associated data self._cache_A = b("") # Cache for unaligned ciphertext/plaintext self._cache_P = b("") # Allowed transitions after initialization self._next = [self.update, self.encrypt, self.decrypt, self.digest, self.verify] # Compute Offset_0 params_without_key = dict(cipher_params) key = params_without_key.pop("key") nonce = bchr(self._mac_len << 4 & 0xFF) + bchr(0) * (14 - len(self.nonce)) + bchr(1) + self.nonce bottom = bord(nonce[15]) & 0x3F # 6 bits, 0..63 ktop = factory.new(key, factory.MODE_ECB, **params_without_key).encrypt( nonce[:15] + bchr(bord(nonce[15]) & 0xC0) ) stretch = ktop + strxor(ktop[:8], ktop[1:9]) # 192 bits offset_0 = long_to_bytes(bytes_to_long(stretch) >> (64 - bottom), 24)[8:] # Create low-level cipher instance raw_cipher = factory._create_base_cipher(cipher_params) if cipher_params: raise TypeError("Unknown keywords: " + str(cipher_params)) self._state = VoidPointer() result = _raw_ocb_lib.OCB_start_operation( raw_cipher.get(), offset_0, c_size_t(len(offset_0)), self._state.address_of() ) if result: raise ValueError("Error %d while instantiating the OCB mode" % result) # Ensure that object disposal of this Python object will (eventually) # free the memory allocated by the raw library for the cipher mode self._state = SmartPointer(self._state.get(), _raw_ocb_lib.OCB_stop_operation) # Memory allocated for the underlying block cipher is now owed # by the cipher mode raw_cipher.release()
def test_nonce_length(self): # nonce can be of any length (but not empty) self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_GCM, nonce=b("")) for x in range(1, 128): cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=bchr(1) * x) cipher.encrypt(bchr(1))
def test_update(self): pieces = [bchr(10) * 200, bchr(20) * 300] h = keccak.new(digest_bytes=64) h.update(pieces[0]).update(pieces[1]) digest = h.digest() h = keccak.new(digest_bytes=64) h.update(pieces[0] + pieces[1]) self.assertEqual(h.digest(), digest)
def _definite_form(length): """Build length octets according to BER/DER definite form. """ if length > 127: encoding = long_to_bytes(length) return bchr(len(encoding) + 128) + encoding return bchr(length)
def test_update(self): pieces = [bchr(10) * 200, bchr(20) * 300] h = self.shake.new() h.update(pieces[0]).update(pieces[1]) digest = h.read(10) h = self.shake.new() h.update(pieces[0] + pieces[1]) self.assertEqual(h.read(10), digest)
def test_update(self): pieces = [bchr(10) * 200, bchr(20) * 300] h = self.BLAKE2.new(digest_bytes=self.max_bytes) h.update(pieces[0]).update(pieces[1]) digest = h.digest() h = self.BLAKE2.new(digest_bytes=self.max_bytes) h.update(pieces[0] + pieces[1]) self.assertEqual(h.digest(), digest)
def runTest(self): self.assertRaises(ValueError, ARC2.new, bchr(0) * 4, ARC2.MODE_ECB) self.assertRaises(ValueError, ARC2.new, bchr(0) * 129, ARC2.MODE_ECB) self.assertRaises(ValueError, ARC2.new, bchr(0) * 16, ARC2.MODE_ECB, effective_keylen=39) self.assertRaises(ValueError, ARC2.new, bchr(0) * 16, ARC2.MODE_ECB, effective_keylen=1025)
def test_nonce_length(self): self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, nonce=b("")) self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, nonce=bchr(1) * 6) self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, nonce=bchr(1) * 14) for x in range(7, 13 + 1): AES.new(self.key_128, AES.MODE_CCM, nonce=bchr(1) * x)
def test_wrap_around(self): counter = Counter.new(8, prefix=bchr(9) * 15) cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) cipher.encrypt(bchr(9) * 16 * 255) self.assertRaises(OverflowError, cipher.encrypt, bchr(9) * 16) cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) cipher.decrypt(bchr(9) * 16 * 255) self.assertRaises(OverflowError, cipher.decrypt, bchr(9) * 16)
def exportSSHKey(self): eb = long_to_bytes(self.e) nb = long_to_bytes(self.n) if bord(eb[0]) & 0x80: eb = bchr(0x00) + eb if bord(nb[0]) & 0x80: nb = bchr(0x00) + nb keyparts = ['ssh-rsa', eb, nb] keystring = ''.join([struct.pack(">I", len(kp)) + kp for kp in keyparts]) return 'ssh-rsa ' + binascii.b2a_base64(keystring)[:-1]
def __init__(self, key, msg=b(""), digestmod=None): """Create a new HMAC object. :Parameters: key : byte string secret key for the MAC object. It must be long enough to match the expected security level of the MAC. However, there is no benefit in using keys longer than the `digest_size` of the underlying hash algorithm. msg : byte string The very first chunk of the message to authenticate. It is equivalent to an early call to `update()`. Optional. :Parameter digestmod: The hash algorithm the HMAC is based on. Default is `Crypto.Hash.MD5`. :Type digestmod: A hash module or object instantiated from `Crypto.Hash` """ if digestmod is None: digestmod = MD5 if msg is None: msg = b("") #: Size of the MAC tag self.digest_size = digestmod.digest_size self._digestmod = digestmod try: if len(key) <= digestmod.block_size: # Step 1 or 2 key_0 = key + bchr(0) * (digestmod.block_size - len(key)) else: # Step 3 hash_k = digestmod.new(key).digest() key_0 = hash_k + bchr(0) * (digestmod.block_size - len(hash_k)) except AttributeError: # Not all hash types have "block_size" raise ValueError("Hash type incompatible to HMAC") # Step 4 key_0_ipad = strxor(key_0, bchr(0x36) * len(key_0)) # Start step 5 and 6 self._inner = digestmod.new(key_0_ipad) self._inner.update(msg) # Step 7 key_0_opad = strxor(key_0, bchr(0x5c) * len(key_0)) # Start step 8 and 9 self._outer = digestmod.new(key_0_opad)
def test_mac_length(self): pt = bchr(9) * 100 self.assertRaises(ValueError, AES.new, self.key, AES.MODE_OCB, nonce=bchr(0)*15, mac_len=7) self.assertRaises(ValueError, AES.new, self.key, AES.MODE_OCB, nonce=bchr(0)*15, mac_len=17) ct, mac = self._create_cipher().encrypt_and_digest(pt) self.assertEquals(len(mac), 16) for mac_len in xrange(8, 16+1): ct, mac = self._create_cipher(mac_len=mac_len).encrypt_and_digest(pt) self.assertEquals(len(mac), mac_len)
def test_round_trip(self): aad = bchr(8) * 100 pt = bchr(9) * 100 cipher = self._create_cipher() cipher.update(aad) ct, mac = cipher.encrypt_and_digest(pt) cipher = self._create_cipher() cipher.update(aad) pt2 = cipher.decrypt_and_verify(ct, mac) self.assertEquals(pt, pt2)
def encode(self): """Return the DER INTEGER, fully encoded as a binary string.""" number = self.value self.payload = b('') while True: self.payload = bchr(int(number & 255)) + self.payload if 128 <= number <= 255: self.payload = bchr(0x00) + self.payload if -128 <= number <= 255: break number >>= 8 return DerObject.encode(self)
def encode(self): """Return this DER element, fully encoded as a binary byte string.""" # Concatenate identifier octets, length octets, # and contents octets output_payload = self.payload # In case of an EXTERNAL tag, first encode the inner # element. if hasattr(self, "_inner_tag_octet"): output_payload = bchr(self._inner_tag_octet) + self._definite_form(len(self.payload)) + self.payload return bchr(self._tag_octet) + self._definite_form(len(output_payload)) + output_payload
def test_seek_tv(self): # Test Vector #4, A.1 from # http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 key = bchr(0) + bchr(255) + bchr(0) * 30 nonce = bchr(0) * 8 cipher = ChaCha20.new(key=key, nonce=nonce) cipher.seek(64 * 2) expected_key_stream = unhexlify(b( "72d54dfbf12ec44b362692df94137f32" "8fea8da73990265ec1bbbea1ae9af0ca" "13b25aa26cb4a648cb9b9d1be65b2c09" "24a66c54d545ec1b7374f4872e99f096" )) ct = cipher.encrypt(bchr(0) * len(expected_key_stream)) self.assertEqual(expected_key_stream, ct)
def verify(self, received_mac_tag): """Validate the *binary* MAC tag. The caller invokes this function at the very end. This method checks if the decrypted message is indeed valid (that is, if the key is correct) and it has not been tampered with while in transit. :Parameters: received_mac_tag : byte string This is the *binary* MAC, as received from the sender. :Raises MacMismatchError: if the MAC does not match. The message has been tampered with or the key is incorrect. """ if self.verify not in self._next: raise TypeError("verify() cannot be called" " when encrypting a message") self._next = [self.verify] if not self._mac_tag: tag = bchr(0) * self.block_size for i in range(3): tag = strxor(tag, self._omac[i].digest()) self._mac_tag = tag[:self._mac_len] secret = get_random_bytes(16) mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=self._mac_tag) mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=received_mac_tag) if mac1.digest() != mac2.digest(): raise ValueError("MAC check failed")
def adjust_key_parity(key_in): """Set the parity bits in a TDES key. :param key_in: the TDES key whose bits need to be adjusted :type key_in: byte string :returns: a copy of ``key_in``, with the parity bits correctly set :rtype: byte string :raises ValueError: if the TDES key is not 16 or 24 bytes long :raises ValueError: if the TDES key degenerates into Single DES """ def parity_byte(key_byte): parity = 1 for i in xrange(1, 8): parity ^= (key_byte >> i) & 1 return (key_byte & 0xFE) | parity if len(key_in) not in key_size: raise ValueError("Not a valid TDES key") key_out = b"".join([ bchr(parity_byte(bord(x))) for x in key_in ]) if key_out[:8] == key_out[8:16] or key_out[-16:-8] == key_out[-8:]: raise ValueError("Triple DES key degenerates to single DES") return key_out
def _start_mac(self): assert(self._mac_status == MacStatus.NOT_STARTED) assert(None not in (self._assoc_len, self._msg_len)) assert(isinstance(self._cache, list)) # Formatting control information and nonce (A.2.1) q = 15 - len(self.nonce) # length of Q, the encoded message length flags = (64 * (self._assoc_len > 0) + 8 * ((self._mac_len - 2) // 2) + (q - 1)) b_0 = bchr(flags) + self.nonce + long_to_bytes(self._msg_len, q) # Formatting associated data (A.2.2) # Encoded 'a' is concatenated with the associated data 'A' assoc_len_encoded = b('') if self._assoc_len > 0: if self._assoc_len < (2 ** 16 - 2 ** 8): enc_size = 2 elif self._assoc_len < (2 ** 32): assoc_len_encoded = b('\xFF\xFE') enc_size = 4 else: assoc_len_encoded = b('\xFF\xFF') enc_size = 8 assoc_len_encoded += long_to_bytes(self._assoc_len, enc_size) # b_0 and assoc_len_encoded must be processed first self._cache.insert(0, b_0) self._cache.insert(1, assoc_len_encoded) # Process all the data cached so far first_data_to_mac = b("").join(self._cache) self._cache = b("") self._mac_status = MacStatus.PROCESSING_AUTH_DATA self._update(first_data_to_mac)
def _export_private_der(self, include_ec_params=True): assert self.has_private() # ECPrivateKey ::= SEQUENCE { # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), # privateKey OCTET STRING, # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, # publicKey [1] BIT STRING OPTIONAL # } # Public key - uncompressed form order_bytes = _curve.order.size_in_bytes() public_key = (bchr(4) + self.pointQ.x.to_bytes(order_bytes) + self.pointQ.y.to_bytes(order_bytes)) seq = [1, DerOctetString(self.d.to_bytes(order_bytes)), DerObjectId(_curve.oid, explicit=0), DerBitString(public_key, explicit=1)] if not include_ec_params: del seq[2] return DerSequence(seq).encode()
def _start_mac(self): assert(self._mac_status == MacStatus.NOT_STARTED) assert(None not in (self._assoc_len, self._msg_len)) assert(isinstance(self._cache, list)) # Formatting control information and nonce (A.2.1) q = 15 - len(self.nonce) # length of Q, the encoded message length flags = (64 * (self._assoc_len > 0) + 8 * ((self._mac_len - 2) // 2) + (q - 1)) b_0 = bchr(flags) + self.nonce + long_to_bytes(self._msg_len, q) # Formatting associated data (A.2.2) # Encoded 'a' is concatenated with the associated data 'A' assoc_len_encoded = b('') if self._assoc_len > 0: if self._assoc_len < (2 ** 16 - 2 ** 8): enc_size = 2 elif self._assoc_len < (2L ** 32): assoc_len_encoded = b('\xFF\xFE') enc_size = 4 else: assoc_len_encoded = b('\xFF\xFF') enc_size = 8 assoc_len_encoded += long_to_bytes(self._assoc_len, enc_size)
def test_aes_encrypt(data=DATA, nonce=NONCE): """ AES Encrypt (256 Bit, CBC Mode, PKCS #7 Padding) """ size = AES.block_size - (len(data) % AES.block_size) data = tobytes(data) + (bchr(size) * size) data = AES.new(nonce[:32], AES.MODE_CBC, nonce[32:]).encrypt(data) return base64.b64encode(data), len(data)
def test_nonce_length(self): # nonce can be of any length (but not empty) self.assertRaises(ValueError, AES.new, self.key_256, AES.MODE_SIV, nonce=b("")) for x in range(1, 128): cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=bchr(1) * x) cipher.encrypt_and_digest(b'\x01')
def __init__(self, factory, key, nonce, mac_len, cipher_params): """EAX cipher mode""" self.block_size = factory.block_size """The block size of the underlying cipher, in bytes.""" self.nonce = nonce """The nonce originally used to create the object.""" self._mac_len = mac_len self._mac_tag = None # Cache for MAC tag # Allowed transitions after initialization self._next = [self.update, self.encrypt, self.decrypt, self.digest, self.verify] # MAC tag length if not (4 <= self._mac_len <= self.block_size): raise ValueError("Parameter 'mac_len' must not be larger than %d" % self.block_size) # Nonce cannot be empty and must be a byte string if len(nonce) == 0: raise ValueError("Nonce cannot be empty in EAX mode") if not byte_string(nonce): raise TypeError("Nonce must be a byte string") self._omac = [ CMAC.new(key, bchr(0) * (self.block_size - 1) + bchr(i), ciphermod=factory, cipher_params=cipher_params) for i in range(0, 3) ] # Compute MAC of nonce self._omac[0].update(nonce) self._signer = self._omac[1] # MAC of the nonce is also the initial counter for CTR encryption counter_int = bytes_to_long(self._omac[0].digest()) self._cipher = factory.new(key, factory.MODE_CTR, initial_value=counter_int, nonce=b(""), **cipher_params)
def test_init(self): # Verify that nonce can be passed in the old way (3rd parameter) # or in the new way ('nonce' parameter) ct, mac = self._create_cipher().encrypt_and_digest(b("XXX")) cipher = AES.new(self.key, AES.MODE_OCB, bchr(0)*15) ct2, mac2 = cipher.encrypt_and_digest(b("XXX")) self.assertEquals(ct, ct2) self.assertEquals(mac, mac2)
def encrypt(self, data): nonce = Random.get_random_bytes(Pssst._Key.NONCE_SIZE) size = AES.block_size - (len(data) % AES.block_size) data = tobytes(data) + (bchr(size) * size) data = AES.new(nonce[:32], AES.MODE_CBC, nonce[32:]).encrypt(data) nonce = PKCS1_OAEP.new(self.key).encrypt(nonce) return (data, nonce)
def bcrypt(password, cost, salt=None): """Hash a password into a key, using the OpenBSD bcrypt protocol. Args: password (byte string or string): The secret password or pass phrase. It must be at most 72 bytes long. It must not contain the zero byte. Unicode strings will be encoded as UTF-8. cost (integer): The exponential factor that makes it slower to compute the hash. It must be in the range 4 to 31. A value of at least 12 is recommended. salt (byte string): Optional. Random byte string to thwarts dictionary and rainbow table attacks. It must be 16 bytes long. If not passed, a random value is generated. Return (byte string): The bcrypt hash Raises: ValueError: if password is longer than 72 bytes or if it contains the zero byte """ password = tobytes(password, "utf-8") if password.find(bchr(0)[0]) != -1: raise ValueError("The password contains the zero byte") if len(password) < 72: password += b"\x00" if salt is None: salt = get_random_bytes(16) if len(salt) != 16: raise ValueError("bcrypt salt must be 16 bytes long") ctext = _bcrypt_hash(password, cost, salt, b"OrpheanBeholderScryDoubt", True) cost_enc = b"$" + bstr(str(cost).zfill(2)) salt_enc = b"$" + _bcrypt_encode(salt) hash_enc = _bcrypt_encode(ctext[:-1]) # only use 23 bytes, not 24 return b"$2a" + cost_enc + salt_enc + hash_enc
def runTest(self): key = b'0' * 16 h = SHA256.new() for length in range(160): nonce = '{0:04d}'.format(length).encode('utf-8') data = bchr(length) * length cipher = AES.new(key, AES.MODE_GCM, nonce=nonce, **self._extra_params) ct, tag = cipher.encrypt_and_digest(data) h.update(ct) h.update(tag) self.assertEqual( h.hexdigest(), "7b7eb1ffbe67a2e53a912067c0ec8e62ebc7ce4d83490ea7426941349811bdf4")
def _export_openssh(self, compress): if self.has_private(): raise ValueError("Cannot export OpenSSH private keys") desc = "ecdsa-sha2-nistp256" order_bytes = _curve.order.size_in_bytes() if compress: first_byte = 2 + self.pointQ.y.is_odd() public_key = (bchr(first_byte) + self.pointQ.x.to_bytes(order_bytes)) else: public_key = (b'\x04' + self.pointQ.x.to_bytes(order_bytes) + self.pointQ.y.to_bytes(order_bytes)) comps = (tobytes(desc), b"nistp256", public_key) blob = b"".join([struct.pack(">I", len(x)) + x for x in comps]) return desc + " " + tostr(binascii.b2a_base64(blob))
def adjust_key_parity(key_in): """Return the TDES key with parity bits correctly set""" def parity_byte(key_byte): parity = 1 for i in xrange(1, 8): parity ^= (key_byte >> i) & 1 return (key_byte & 0xFE) | parity if len(key_in) not in key_size: raise ValueError("Not a valid TDES key") key_out = b("").join([ bchr(parity_byte(bord(x)) )for x in key_in ]) if key_out[:8] == key_out[8:16] or key_out[-16:-8] == key_out[-8:]: raise ValueError("Triple DES key degenerates to single DES") return key_out
def runTest(self): key = b'0' * 16 h = SHA256.new() for length in range(160): nonce = '{0:04d}'.format(length).encode('utf-8') data = bchr(length) * length cipher = AES.new(key, AES.MODE_GCM, nonce=nonce, **self._extra_params) ct, tag = cipher.encrypt_and_digest(data) h.update(ct) h.update(tag) self.assertEqual( h.hexdigest(), '1057d9559f55227fd4e36bab8716ebcfe6671b5603fdceb046a33591175ee5e4')
def test_wrap_around(self): # Counter is only 8 bits, so we can only encrypt/decrypt 256 blocks (=4096 bytes) counter = Counter.new(8, prefix=bchr(9) * 15) max_bytes = 4096 cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) cipher.encrypt(b'9' * max_bytes) self.assertRaises(OverflowError, cipher.encrypt, b'9') cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) self.assertRaises(OverflowError, cipher.encrypt, b'9' * (max_bytes + 1)) cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) cipher.decrypt(b'9' * max_bytes) self.assertRaises(OverflowError, cipher.decrypt, b'9') cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) self.assertRaises(OverflowError, cipher.decrypt, b'9' * (max_bytes + 1))
def _export_openssh(self, compress): if self.has_private(): raise ValueError("Cannot export OpenSSH private keys") desc = self._curve.openssh modulus_bytes = self.pointQ.size_in_bytes() if compress: first_byte = 2 + self.pointQ.y.is_odd() public_key = (bchr(first_byte) + self.pointQ.x.to_bytes(modulus_bytes)) else: public_key = (b'\x04' + self.pointQ.x.to_bytes(modulus_bytes) + self.pointQ.y.to_bytes(modulus_bytes)) middle = desc.split("-")[2] comps = (tobytes(desc), tobytes(middle), public_key) blob = b"".join([struct.pack(">I", len(x)) + x for x in comps]) return desc + " " + tostr(binascii.b2a_base64(blob))
def down_transform(self, byte_sequence: bytes, last: bool = False): if self._finished_last: return bytes([]) first = self._first if first: initialization_vector = byte_sequence[:AES.block_size] self._aes = AES.new(self._key, AES.MODE_CBC, initialization_vector) self._first = False decrypted_data = self._aes.decrypt( byte_sequence[AES.block_size:]) if first else self._aes.decrypt( byte_sequence) # Cut padding if last: padding = bord(decrypted_data[-1]) if decrypted_data[-padding:] != bchr(padding) * padding: raise ValueError('PKCS#7 padding is incorrect') self._finished_last = True return decrypted_data[:-padding] return decrypted_data
def __init__(self, factory, key, iv, cipher_params): #: The block size of the underlying cipher, in bytes. self.block_size = factory.block_size self._done_first_block = False # True after the first encryption # Instantiate a temporary cipher to process the IV IV_cipher = factory.new(key, factory.MODE_CFB, IV=bchr(0) * self.block_size, segment_size=self.block_size * 8, **cipher_params) # The cipher will be used for... if len(iv) == self.block_size: # ... encryption self._encrypted_IV = IV_cipher.encrypt(iv + iv[-2:]) elif len(iv) == self.block_size + 2: # ... decryption self._encrypted_IV = iv iv = IV_cipher.decrypt(iv) if iv[-2:] != iv[-4:-2]: raise ValueError("Failed integrity check for OPENPGP IV") iv = iv[:-2] else: raise ValueError("Length of IV must be %d or %d bytes" " for MODE_OPENPGP" % (self.block_size, self.block_size + 2)) self.iv = self.IV = iv # Instantiate the cipher for the real PGP data self._cipher = factory.new(key, factory.MODE_CFB, IV=self._encrypted_IV[-self.block_size:], segment_size=self.block_size * 8, **cipher_params)
def _export_subjectPublicKeyInfo(self, compress): # See 2.2 in RFC5480 and 2.3.3 in SEC1 # The first byte is: # - 0x02: compressed, only X-coordinate, Y-coordinate is even # - 0x03: compressed, only X-coordinate, Y-coordinate is odd # - 0x04: uncompressed, X-coordinate is followed by Y-coordinate # # PAI is in theory encoded as 0x00. modulus_bytes = self.pointQ.size_in_bytes() if compress: first_byte = 2 + self.pointQ.y.is_odd() public_key = (bchr(first_byte) + self.pointQ.x.to_bytes(modulus_bytes)) else: public_key = (b'\x04' + self.pointQ.x.to_bytes(modulus_bytes) + self.pointQ.y.to_bytes(modulus_bytes)) unrestricted_oid = "1.2.840.10045.2.1" return _create_subject_public_key_info(unrestricted_oid, public_key, DerObjectId(self._curve.oid))
def test_byte_by_byte_confidentiality(self): pt = bchr(3) * 101 ct, mac = self._create_cipher().encrypt_and_digest(pt) # Encryption cipher = self._create_cipher() ct2 = b("") for x in range(len(pt)): ct2 += cipher.encrypt(pt[x:x + 1]) ct2 += cipher.encrypt() mac2 = cipher.digest() self.assertEqual(ct, ct2) self.assertEqual(mac, mac2) # Decryption cipher = self._create_cipher() pt2 = b("") for x in range(len(ct)): pt2 += cipher.decrypt(ct[x:x + 1]) pt2 += cipher.decrypt() self.assertEqual(pt, pt2) cipher.verify(mac)
def digest(self): """Compute the *binary* MAC tag. The caller invokes this function at the very end. This method returns the MAC that shall be sent to the receiver, together with the ciphertext. :Return: the MAC, as a byte string. """ if self.digest not in self._next: raise TypeError("digest() cannot be called when decrypting" " or validating a message") self._next = [self.digest] if not self._mac_tag: tag = bchr(0) * self.block_size for i in xrange(3): tag = strxor(tag, self._omac[i].digest()) self._mac_tag = tag[:self._mac_len] return self._mac_tag
def to_bytes(self, block_size=0): """Convert the number into a byte string. This method encodes the number in network order and prepends as many zero bytes as required. It only works for non-negative values. :Parameters: block_size : integer The exact size the output byte string must have. If zero, the string has the minimal length. :Returns: A byte string. :Raise ValueError: If the value is negative or if ``block_size`` is provided and the length of the byte string would exceed it. """ if self < 0: raise ValueError("Conversion only valid for non-negative numbers") buf_len = (_gmp.mpz_sizeinbase(self._mpz_p, 2) + 7) // 8 if buf_len > block_size > 0: raise ValueError("Number is too big to convert to byte string" "of prescribed length") buf = create_string_buffer(buf_len) _gmp.mpz_export( buf, null_pointer, # Ignore countp 1, # Big endian c_size_t(1), # Each word is 1 byte long 0, # Endianess within a word - not relevant c_size_t(0), # No nails self._mpz_p) return bchr(0) * max(0, block_size - buf_len) + get_raw_buffer(buf)
def __init__(self, factory, key, iv, cipher_params): #: The block size of the underlying cipher, in bytes. self.block_size = factory.block_size self._done_first_block = False # True after the first encryption # Instantiate a temporary cipher to process the IV IV_cipher = factory.new(key, factory.MODE_CFB, IV=bchr(0) * self.block_size, segment_size=self.block_size * 8, **cipher_params) # The cipher will be used for... if len(iv) == self.block_size: # ... encryption self._encrypted_IV = IV_cipher.encrypt(iv + iv[-2:]) elif len(iv) == self.block_size + 2: # ... decryption self._encrypted_IV = iv # Last two bytes are for a deprecated "quick check" feature that # should not be used. (https://eprint.iacr.org/2005/033) iv = IV_cipher.decrypt(iv)[:-2] else: raise ValueError("Length of IV must be %d or %d bytes" " for MODE_OPENPGP" % (self.block_size, self.block_size + 2)) self.iv = self.IV = bstr(iv) # Instantiate the cipher for the real PGP data self._cipher = factory.new(key, factory.MODE_CFB, IV=self._encrypted_IV[-self.block_size:], segment_size=self.block_size * 8, **cipher_params)
def test_invalid_nonce_length(self): key = bchr(1) * 16 self.assertRaises(ValueError, Salsa20.new, key, bchr(0) * 7) self.assertRaises(ValueError, Salsa20.new, key, bchr(0) * 9)
def runTest(self): nonce = bchr(0) * 8 for key_length in (15, 30, 33): key = bchr(1) * key_length self.assertRaises(ValueError, Salsa20.new, key, nonce)
def pkcs7pad(msg, blocklen): paddinglen = blocklen - len(msg) % blocklen padding = bchr(paddinglen) * paddinglen return msg + padding
def newMGF(seed,maskLen): global mgfcalls mgfcalls += 1 return bchr(0x00)*maskLen
def runTest(self): self.assertRaises(ValueError, Blowfish.new, bchr(0) * 4, Blowfish.MODE_ECB) self.assertRaises(ValueError, Blowfish.new, bchr(0) * 57, Blowfish.MODE_ECB)
def pad(data_to_pad, block_size): padding_len = block_size - len(data_to_pad) % block_size padding = bchr(padding_len) * padding_len return data_to_pad + padding
def test_default_nonce(self): cipher1 = ChaCha20.new(key=bchr(1) * 32) cipher2 = ChaCha20.new(key=bchr(1) * 32) self.assertEqual(len(cipher1.nonce), 8) self.assertNotEqual(cipher1.nonce, cipher2.nonce)
def testDecrypt2(self): # Simplest possible negative tests for ct_size in (127,128,129): cipher = PKCS.new(self.key1024) self.assertRaises(ValueError, cipher.decrypt, bchr(0x00)*ct_size)
def test_default_nonce(self): cipher1 = Salsa20.new(bchr(1) * 16) cipher2 = Salsa20.new(bchr(1) * 16) self.assertEqual(len(cipher1.nonce), 8) self.assertNotEqual(cipher1.nonce, cipher2.nonce)
def _create_ctr_cipher(factory, **kwargs): """Instantiate a cipher object that performs CTR encryption/decryption. :Parameters: factory : module The underlying block cipher, a module from ``Crypto.Cipher``. :Keywords: nonce : binary string/array The fixed part at the beginning of the counter block - the rest is the counter number that gets increased when processing the next block. The nonce must be such that no two messages are encrypted under the same key and the same nonce. The nonce must be shorter than the block size (it can have zero length; the counter is then as long as the block). If this parameter is not present, a random nonce will be created with length equal to half the block size. No random nonce shorter than 64 bits will be created though - you must really think through all security consequences of using such a short block size. initial_value : posive integer or byte string/array The initial value for the counter. If not present, the cipher will start counting from 0. The value is incremented by one for each block. The counter number is encoded in big endian mode. counter : object Instance of ``Crypto.Util.Counter``, which allows full customization of the counter block. This parameter is incompatible to both ``nonce`` and ``initial_value``. Any other keyword will be passed to the underlying block cipher. See the relevant documentation for details (at least ``key`` will need to be present). """ cipher_state = factory._create_base_cipher(kwargs) counter = kwargs.pop("counter", None) nonce = kwargs.pop("nonce", None) initial_value = kwargs.pop("initial_value", None) if kwargs: raise TypeError("Invalid parameters for CTR mode: %s" % str(kwargs)) if counter is not None and (nonce, initial_value) != (None, None): raise TypeError("'counter' and 'nonce'/'initial_value'" " are mutually exclusive") if counter is None: # Crypto.Util.Counter is not used if nonce is None: if factory.block_size < 16: raise TypeError("Impossible to create a safe nonce for short" " block sizes") nonce = get_random_bytes(factory.block_size // 2) else: if len(nonce) >= factory.block_size: raise ValueError("Nonce is too long") # What is not nonce is counter counter_len = factory.block_size - len(nonce) if initial_value is None: initial_value = 0 if isinstance(initial_value, (int, long)): if (1 << (counter_len * 8)) - 1 < initial_value: raise ValueError("Initial counter value is too large") initial_counter_block = nonce + long_to_bytes( initial_value, counter_len) else: if len(initial_value) != counter_len: raise ValueError( "Incorrect length for counter byte string (%d bytes, expected %d)" % (len(initial_value), counter_len)) initial_counter_block = nonce + initial_value return CtrMode( cipher_state, initial_counter_block, len(nonce), # prefix counter_len, False) # little_endian # Crypto.Util.Counter is used # 'counter' used to be a callable object, but now it is # just a dictionary for backward compatibility. _counter = dict(counter) try: counter_len = _counter.pop("counter_len") prefix = _counter.pop("prefix") suffix = _counter.pop("suffix") initial_value = _counter.pop("initial_value") little_endian = _counter.pop("little_endian") except KeyError: raise TypeError("Incorrect counter object" " (use Crypto.Util.Counter.new)") # Compute initial counter block words = [] while initial_value > 0: words.append(bchr(initial_value & 255)) initial_value >>= 8 words += [bchr(0)] * max(0, counter_len - len(words)) if not little_endian: words.reverse() initial_counter_block = prefix + b("").join(words) + suffix if len(initial_counter_block) != factory.block_size: raise ValueError("Size of the counter block (%d bytes) must match" " block size (%d)" % (len(initial_counter_block), factory.block_size)) return CtrMode(cipher_state, initial_counter_block, len(prefix), counter_len, little_endian)
def exportKey(self, format='PEM', passphrase=None, pkcs=1, protection=None, randfunc=None): """Export this RSA key. Args: format (string): The format to use for wrapping the key: - *'PEM'*. (*Default*) Text encoding, done according to `RFC1421`_/`RFC1423`_. - *'DER'*. Binary encoding. - *'OpenSSH'*. Textual encoding, done according to OpenSSH specification. Only suitable for public keys (not private keys). passphrase (string): (*For private keys only*) The pass phrase used for protecting the output. pkcs (integer): (*For private keys only*) The ASN.1 structure to use for serializing the key. Note that even in case of PEM encoding, there is an inner ASN.1 DER structure. With ``pkcs=1`` (*default*), the private key is encoded in a simple `PKCS#1`_ structure (``RSAPrivateKey``). With ``pkcs=8``, the private key is encoded in a `PKCS#8`_ structure (``PrivateKeyInfo``). .. note:: This parameter is ignored for a public key. For DER and PEM, an ASN.1 DER ``SubjectPublicKeyInfo`` structure is always used. protection (string): (*For private keys only*) The encryption scheme to use for protecting the private key. If ``None`` (default), the behavior depends on :attr:`format`: - For *'DER'*, the *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC* scheme is used. The following operations are performed: 1. A 16 byte Triple DES key is derived from the passphrase using :func:`Crypto.Protocol.KDF.PBKDF2` with 8 bytes salt, and 1 000 iterations of :mod:`Crypto.Hash.HMAC`. 2. The private key is encrypted using CBC. 3. The encrypted key is encoded according to PKCS#8. - For *'PEM'*, the obsolete PEM encryption scheme is used. It is based on MD5 for key derivation, and Triple DES for encryption. Specifying a value for :attr:`protection` is only meaningful for PKCS#8 (that is, ``pkcs=8``) and only if a pass phrase is present too. The supported schemes for PKCS#8 are listed in the :mod:`Crypto.IO.PKCS8` module (see :attr:`wrap_algo` parameter). randfunc (callable): A function that provides random bytes. Only used for PEM encoding. The default is :func:`Crypto.Random.get_random_bytes`. Returns: byte string: the encoded key Raises: ValueError:when the format is unknown or when you try to encrypt a private key with *DER* format and PKCS#1. .. warning:: If you don't provide a pass phrase, the private key will be exported in the clear! .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt .. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt """ if passphrase is not None: passphrase = tobytes(passphrase) if randfunc is None: randfunc = Random.get_random_bytes if format == 'OpenSSH': e_bytes, n_bytes = [x.to_bytes() for x in (self._e, self._n)] if bord(e_bytes[0]) & 0x80: e_bytes = bchr(0) + e_bytes if bord(n_bytes[0]) & 0x80: n_bytes = bchr(0) + n_bytes keyparts = [b('ssh-rsa'), e_bytes, n_bytes] keystring = b('').join( [struct.pack(">I", len(kp)) + kp for kp in keyparts]) return b('ssh-rsa ') + binascii.b2a_base64(keystring)[:-1] # DER format is always used, even in case of PEM, which simply # encodes it into BASE64. if self.has_private(): binary_key = DerSequence([ 0, self.n, self.e, self.d, self.p, self.q, self.d % (self.p - 1), self.d % (self.q - 1), Integer(self.q).inverse(self.p) ]).encode() if pkcs == 1: key_type = 'RSA PRIVATE KEY' if format == 'DER' and passphrase: raise ValueError("PKCS#1 private key cannot be encrypted") else: # PKCS#8 if format == 'PEM' and protection is None: key_type = 'PRIVATE KEY' binary_key = PKCS8.wrap(binary_key, oid, None) else: key_type = 'ENCRYPTED PRIVATE KEY' if not protection: protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' binary_key = PKCS8.wrap(binary_key, oid, passphrase, protection) passphrase = None else: key_type = "PUBLIC KEY" binary_key = _create_subject_public_key_info( oid, DerSequence([self.n, self.e])) if format == 'DER': return binary_key if format == 'PEM': pem_str = PEM.encode(binary_key, key_type, passphrase, randfunc) return tobytes(pem_str) raise ValueError( "Unknown key format '%s'. Cannot export the RSA key." % format)
def __init__(self, key, msg=None, ciphermod=None, cipher_params=None): if ciphermod is None: raise TypeError("ciphermod must be specified (try AES)") self._key = key self._factory = ciphermod if cipher_params is None: self._cipher_params = {} else: self._cipher_params = dict(cipher_params) # Section 5.3 of NIST SP 800 38B and Appendix B if ciphermod.block_size == 8: const_Rb = 0x1B self._max_size = 8 * (2 ** 21) elif ciphermod.block_size == 16: const_Rb = 0x87 self._max_size = 16 * (2 ** 48) else: raise TypeError("CMAC requires a cipher with a block size" "of 8 or 16 bytes, not %d" % (ciphermod.block_size,)) # Size of the final MAC tag, in bytes self.digest_size = ciphermod.block_size self._mac_tag = None # Compute sub-keys zero_block = bchr(0) * ciphermod.block_size cipher = ciphermod.new(key, ciphermod.MODE_ECB, **self._cipher_params) l = cipher.encrypt(zero_block) if bord(l[0]) & 0x80: self._k1 = _shift_bytes(l, const_Rb) else: self._k1 = _shift_bytes(l) if bord(self._k1[0]) & 0x80: self._k2 = _shift_bytes(self._k1, const_Rb) else: self._k2 = _shift_bytes(self._k1) # Initialize CBC cipher with zero IV self._cbc = ciphermod.new(key, ciphermod.MODE_CBC, zero_block, **self._cipher_params) # Cache for outstanding data to authenticate self._cache = b("") # Last two pieces of ciphertext produced self._last_ct = self._last_pt = zero_block self._before_last_ct = None # Counter for total message size self._data_size = 0 if msg: self.update(msg)
def __init__(self, factory, key, nonce, mac_len, cipher_params): self.block_size = factory.block_size if self.block_size != 16: raise ValueError("GCM mode is only available for ciphers" " that operate on 128 bits blocks") if len(nonce) == 0: raise ValueError("Nonce cannot be empty") if not byte_string(nonce): raise TypeError("Nonce must be a byte string") self.nonce = nonce """Nonce""" self._factory = factory self._key = key self._tag = None # Cache for MAC tag self._mac_len = mac_len if not (4 <= mac_len <= 16): raise ValueError("Parameter 'mac_len' must be in the range 4..16") # Allowed transitions after initialization self._next = [self.update, self.encrypt, self.decrypt, self.digest, self.verify] self._no_more_assoc_data = False # Length of associated data self._auth_len = 0 # Length of the ciphertext or plaintext self._msg_len = 0 # Step 1 in SP800-38D, Algorithm 4 (encryption) - Compute H # See also Algorithm 5 (decryption) hash_subkey = factory.new(key, self._factory.MODE_ECB, **cipher_params ).encrypt(bchr(0) * 16) # Step 2 - Compute J0 (integer, not byte string!) if len(nonce) == 12: self._j0 = bytes_to_long(nonce + b("\x00\x00\x00\x01")) else: fill = (16 - (len(nonce) % 16)) % 16 + 8 ghash_in = (nonce + bchr(0) * fill + long_to_bytes(8 * len(nonce), 8)) self._j0 = bytes_to_long(_GHASH(hash_subkey) .update(ghash_in) .digest()) # Step 3 - Prepare GCTR cipher for encryption/decryption self._cipher = factory.new(key, self._factory.MODE_CTR, initial_value=self._j0 + 1, nonce=b(""), **cipher_params) # Step 5 - Bootstrat GHASH self._signer = _GHASH(hash_subkey) # Step 6 - Prepare GCTR cipher for GMAC self._tag_cipher = factory.new(key, self._factory.MODE_CTR, initial_value=self._j0, nonce=b(""), **cipher_params) # Cache for data to authenticate self._cache = b("") self._status = MacStatus.PROCESSING_AUTH_DATA
def runTest(self): self.assertRaises(ValueError, CAST.new, bchr(0) * 4, CAST.MODE_ECB) self.assertRaises(ValueError, CAST.new, bchr(0) * 17, CAST.MODE_ECB)
def __init__(self, factory, key, nonce, mac_len, msg_len, assoc_len, cipher_params): self.block_size = factory.block_size """The block size of the underlying cipher, in bytes.""" self.nonce = bstr(nonce) """The nonce used for this cipher instance""" self._factory = factory self._key = bstr(key) self._mac_len = mac_len self._msg_len = msg_len self._assoc_len = assoc_len self._cipher_params = cipher_params self._mac_tag = None # Cache for MAC tag if self.block_size != 16: raise ValueError("CCM mode is only available for ciphers" " that operate on 128 bits blocks") # MAC tag length (Tlen) if mac_len not in (4, 6, 8, 10, 12, 14, 16): raise ValueError("Parameter 'mac_len' must be even" " and in the range 4..16 (not %d)" % mac_len) # Nonce value if not (nonce and 7 <= len(nonce) <= 13): raise ValueError("Length of parameter 'nonce' must be" " in the range 7..13 bytes") # Create MAC object (the tag will be the last block # bytes worth of ciphertext) self._mac = self._factory.new(key, factory.MODE_CBC, iv=bchr(0) * 16, **cipher_params) self._mac_status = MacStatus.NOT_STARTED self._t = None # Allowed transitions after initialization self._next = [self.update, self.encrypt, self.decrypt, self.digest, self.verify] # Cumulative lengths self._cumul_assoc_len = 0 self._cumul_msg_len = 0 # Cache for unaligned associated data/plaintext. # This is a list, but when the MAC starts, it will become a binary # string no longer than the block size. self._cache = [] # Start CTR cipher, by formatting the counter (A.3) q = 15 - len(nonce) # length of Q, the encoded message length self._cipher = self._factory.new(key, self._factory.MODE_CTR, nonce=bchr(q - 1) + nonce, **cipher_params) # S_0, step 6 in 6.1 for j=0 self._s_0 = self._cipher.encrypt(bchr(0) * 16) # Try to start the MAC if None not in (assoc_len, msg_len): self._start_mac()
def import_openssh_private_generic(data, password): # https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key?annotate=HEAD # https://github.com/openssh/openssh-portable/blob/master/sshkey.c # https://coolaj86.com/articles/the-openssh-private-key-format/ # https://coolaj86.com/articles/the-ssh-public-key-format/ if not data.startswith(b'openssh-key-v1\x00'): raise ValueError("Incorrect magic value") data = data[15:] ciphername, data = read_string(data) kdfname, data = read_string(data) kdfoptions, data = read_bytes(data) number_of_keys, data = read_int4(data) if number_of_keys != 1: raise ValueError("We only handle 1 key at a time") _, data = read_string(data) # Public key encrypted, data = read_bytes(data) if data: raise ValueError("Too much data") if len(encrypted) % 8 != 0: raise ValueError("Incorrect payload length") # Decrypt if necessary if ciphername == 'none': decrypted = encrypted else: if (ciphername, kdfname) != ('aes256-ctr', 'bcrypt'): raise ValueError("Unsupported encryption scheme %s/%s" % (ciphername, kdfname)) salt, kdfoptions = read_bytes(kdfoptions) iterations, kdfoptions = read_int4(kdfoptions) if len(salt) != 16: raise ValueError("Incorrect salt length") if kdfoptions: raise ValueError("Too much data in kdfoptions") pwd_sha512 = SHA512.new(password).digest() # We need 32+16 = 48 bytes, therefore 2 bcrypt outputs are sufficient stripes = [] constant = b"OxychromaticBlowfishSwatDynamite" for count in range(1, 3): salt_sha512 = SHA512.new(salt + struct.pack(">I", count)).digest() out_le = _bcrypt_hash(pwd_sha512, 6, salt_sha512, constant, False) out = struct.pack("<IIIIIIII", *struct.unpack(">IIIIIIII", out_le)) acc = bytearray(out) for _ in range(1, iterations): out_le = _bcrypt_hash(pwd_sha512, 6, SHA512.new(out).digest(), constant, False) out = struct.pack("<IIIIIIII", *struct.unpack(">IIIIIIII", out_le)) strxor(acc, out, output=acc) stripes.append(acc[:24]) result = b"".join([bchr(a) + bchr(b) for (a, b) in zip(*stripes)]) cipher = AES.new(result[:32], AES.MODE_CTR, nonce=b"", initial_value=result[32:32 + 16]) decrypted = cipher.decrypt(encrypted) checkint1, decrypted = read_int4(decrypted) checkint2, decrypted = read_int4(decrypted) if checkint1 != checkint2: raise ValueError("Incorrect checksum") ssh_name, decrypted = read_string(decrypted) return ssh_name, decrypted