def __init__(self, key, msg, ciphermod, cipher_params, mac_len, update_after_digest): self.digest_size = mac_len self._key = _copy_bytes(None, None, key) self._factory = ciphermod self._cipher_params = cipher_params self._block_size = bs = ciphermod.block_size self._mac_tag = None self._update_after_digest = update_after_digest # Section 5.3 of NIST SP 800 38B and Appendix B if bs == 8: const_Rb = 0x1B self._max_size = 8 * (2**21) elif bs == 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" % bs) # Compute sub-keys zero_block = b'\x00' * bs self._ecb = ciphermod.new(key, ciphermod.MODE_ECB, **self._cipher_params) L = self._ecb.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 = bytearray(bs) self._cache_n = 0 # Last piece of ciphertext produced self._last_ct = zero_block # Last block that was encrypted with AES self._last_pt = None # Counter for total message size self._data_size = 0 if msg: self.update(msg)
def _import_openssh_private_ecc(data, password): from ._openssh import (import_openssh_private_generic, read_bytes, read_string, check_padding) ssh_name, decrypted = import_openssh_private_generic(data, password) name, decrypted = read_string(decrypted) if name not in _curves: raise UnsupportedEccFeature("Unsupported ECC curve %s" % name) curve = _curves[name] modulus_bytes = (curve.modulus_bits + 7) // 8 public_key, decrypted = read_bytes(decrypted) if bord(public_key[0]) != 4: raise ValueError("Only uncompressed OpenSSH EC keys are supported") if len(public_key) != 2 * modulus_bytes + 1: raise ValueError("Incorrect public key length") point_x = Integer.from_bytes(public_key[1:1 + modulus_bytes]) point_y = Integer.from_bytes(public_key[1 + modulus_bytes:]) point = EccPoint(point_x, point_y, curve=name) private_key, decrypted = read_bytes(decrypted) d = Integer.from_bytes(private_key) _, padded = read_string(decrypted) # Comment check_padding(padded) return EccKey(curve=name, d=d, point=point)
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 range(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 hexdigest(self): """Compute the *printable* MAC tag. This method is like `digest`. :Return: the MAC, as a hexadecimal string. """ return "".join(["%02x" % bord(x) for x in self.digest()])
def hexdigest(self): """Return the **printable** MAC tag of the message authenticated so far. :return: The MAC tag, computed over the data processed so far. Hexadecimal encoded. :rtype: string """ return "".join(["%02x" % bord(x) for x in tuple(self.digest())])
def hexdigest(self): """Return the **printable** digest of the message that has been hashed so far. :return: The hash digest, computed over the data processed so far. Hexadecimal encoded. :rtype: string """ return "".join(["%02x" % bord(x) for x in self.digest()])
def _convertTag(self, tag): """Check if *tag* is a real DER tag. Convert it from a character to number if necessary. """ if not _is_number(tag): if len(tag) == 1: tag = bord(tag[0]) # Ensure that tag is a low tag if not (_is_number(tag) and 0 <= tag < 0x1F): raise ValueError("Wrong DER tag") return tag
def hexdigest(self): """Return the **printable** digest of the message that has been hashed so far. This method does not change the state of the hash object. :Return: A string of 2* `digest_size` characters. It contains only hexadecimal ASCII digits. """ return "".join(["%02x" % bord(x) for x in self.digest()])
def _decodeFromStream(self, s, strict): """Decode a complete DER BIT STRING DER from a file.""" # Fill-up self.payload DerObject._decodeFromStream(self, s, strict) if self.payload and bord(self.payload[0]) != 0: raise ValueError("Not a valid BIT STRING") # Fill-up self.value self.value = b'' # Remove padding count byte if self.payload: self.value = self.payload[1:]
def _decodeFromStream(self, s, strict): """Decode a complete DER INTEGER from a file.""" # Fill up self.payload DerObject._decodeFromStream(self, s, strict) if strict: if len(self.payload) == 0: raise ValueError( "Invalid encoding for DER INTEGER: empty payload") if len(self.payload) >= 2 and struct.unpack( '>H', self.payload[:2])[0] < 0x80: raise ValueError( "Invalid encoding for DER INTEGER: leading zero") # Derive self.value from self.payload self.value = 0 bits = 1 for i in self.payload: self.value *= 256 self.value += bord(i) bits <<= 8 if self.payload and bord(self.payload[0]) & 0x80: self.value -= bits
def _decodeLen(self, s): """Decode DER length octets from a file.""" length = s.read_byte() if length > 127: encoded_length = s.read(length & 0x7F) if bord(encoded_length[0]) == 0: raise ValueError("Invalid DER: length has leading zero") length = bytes_to_long(encoded_length) if length <= 127: raise ValueError( "Invalid DER: length in long form but smaller than 128") return length
def test_asn1_encoding(self): """Verify ASN.1 encoding""" self.description = "ASN.1 encoding test" hash_obj = SHA256.new() signer = DSS.new(self.key_priv, 'fips-186-3', 'der') signature = signer.sign(hash_obj) # Verify that output looks like a DER SEQUENCE self.assertEqual(bord(signature[0]), 48) signer.verify(hash_obj, signature) # Verify that ASN.1 parsing fails as expected signature = bchr(7) + signature[1:] self.assertRaises(ValueError, signer.verify, hash_obj, signature)
def random(cls, **kwargs): """Generate a random natural integer of a certain size. :Keywords: exact_bits : positive integer The length in bits of the resulting random Integer number. The number is guaranteed to fulfil the relation: 2^bits > result >= 2^(bits - 1) max_bits : positive integer The maximum length in bits of the resulting random Integer number. The number is guaranteed to fulfil the relation: 2^bits > result >=0 randfunc : callable A function that returns a random byte string. The length of the byte string is passed as parameter. Optional. If not provided (or ``None``), randomness is read from the system RNG. :Return: a Integer object """ exact_bits = kwargs.pop("exact_bits", None) max_bits = kwargs.pop("max_bits", None) randfunc = kwargs.pop("randfunc", None) if randfunc is None: randfunc = Random.new().read if exact_bits is None and max_bits is None: raise ValueError( "Either 'exact_bits' or 'max_bits' must be specified") if exact_bits is not None and max_bits is not None: raise ValueError( "'exact_bits' and 'max_bits' are mutually exclusive") bits = exact_bits or max_bits bytes_needed = ((bits - 1) // 8) + 1 significant_bits_msb = 8 - (bytes_needed * 8 - bits) msb = bord(randfunc(1)[0]) if exact_bits is not None: msb |= 1 << (significant_bits_msb - 1) msb &= (1 << significant_bits_msb) - 1 return cls.from_bytes(bchr(msb) + randfunc(bytes_needed - 1))
def encrypt(self, message): """Produce the PKCS#1 v1.5 encryption of a message. This function is named ``RSAES-PKCS1-V1_5-ENCRYPT``, and it is specified in `section 7.2.1 of RFC8017 <https://tools.ietf.org/html/rfc8017#page-28>`_. :param message: The message to encrypt, also known as plaintext. It can be of variable length, but not longer than the RSA modulus (in bytes) minus 11. :type message: bytes/bytearray/memoryview :Returns: A byte string, the ciphertext in which the message is encrypted. It is as long as the RSA modulus (in bytes). :Raises ValueError: If the RSA key length is not sufficiently long to deal with the given message. """ # See 7.2.1 in RFC8017 modBits = Crypto.Util.number.size(self._key.n) k = ceil_div(modBits, 8) # Convert from bits to bytes mLen = len(message) # Step 1 if mLen > k - 11: raise ValueError("Plaintext is too long.") # Step 2a ps = [] while len(ps) != k - mLen - 3: new_byte = self._randfunc(1) if bord(new_byte[0]) == 0x00: continue ps.append(new_byte) ps = b"".join(ps) assert (len(ps) == k - mLen - 3) # Step 2b em = b'\x00\x02' + ps + b'\x00' + _copy_bytes(None, None, message) # Step 3a (OS2IP) em_int = bytes_to_long(em) # Step 3b (RSAEP) m_int = self._key._encrypt(em_int) # Step 3c (I2OSP) c = long_to_bytes(m_int, k) return c
def _import_public_der(curve_oid, ec_point): """Convert an encoded EC point into an EccKey object curve_name: string with the OID of the curve ec_point: byte string with the EC point (not DER encoded) """ for curve_name, curve in _curves.items(): if curve.oid == curve_oid: break else: raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_oid) # 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 = curve.p.size_in_bytes() point_type = bord(ec_point[0]) # Uncompressed point if point_type == 0x04: if len(ec_point) != (1 + 2 * modulus_bytes): raise ValueError("Incorrect EC point length") x = Integer.from_bytes(ec_point[1:modulus_bytes + 1]) y = Integer.from_bytes(ec_point[modulus_bytes + 1:]) # Compressed point elif point_type in (0x02, 0x3): if len(ec_point) != (1 + modulus_bytes): raise ValueError("Incorrect EC point length") x = Integer.from_bytes(ec_point[1:]) y = (x**3 - x * 3 + curve.b).sqrt(curve.p) # Short Weierstrass if point_type == 0x02 and y.is_odd(): y = curve.p - y if point_type == 0x03 and y.is_even(): y = curve.p - y else: raise ValueError("Incorrect EC point encoding") return construct(curve=curve_name, point_x=x, point_y=y)
def add(self, elem): """Add an element to the set. Args: elem (byte string or integer): An element of the same type of objects already in the set. It can be an integer or a DER encoded object. """ if _is_number(elem): eo = 0x02 elif isinstance(elem, DerObject): eo = self._tag_octet else: eo = bord(elem[0]) if self._elemOctet != eo: if self._elemOctet is not None: raise ValueError("New element does not belong to the set") self._elemOctet = eo if elem not in self._seq: self._seq.append(elem)
def import_key(extern_key, passphrase=None): """Import a DSA key. Args: extern_key (string or byte string): The DSA key to import. The following formats are supported for a DSA **public** key: - X.509 certificate (binary DER or PEM) - X.509 ``subjectPublicKeyInfo`` (binary DER or PEM) - OpenSSH (ASCII one-liner, see `RFC4253`_) The following formats are supported for a DSA **private** key: - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo`` DER SEQUENCE (binary or PEM) - OpenSSL/OpenSSH custom format (binary or PEM) For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. passphrase (string): In case of an encrypted private key, this is the pass phrase from which the decryption key is derived. Encryption may be applied either at the `PKCS#8`_ or at the PEM level. Returns: :class:`DsaKey` : a DSA key object Raises: ValueError : when the given key cannot be parsed (possibly because the pass phrase is wrong). .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt .. _RFC4253: http://www.ietf.org/rfc/rfc4253.txt .. _PKCS#8: http://www.ietf.org/rfc/rfc5208.txt """ extern_key = tobytes(extern_key) if passphrase is not None: passphrase = tobytes(passphrase) if extern_key.startswith(b'-----'): # This is probably a PEM encoded key (der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase) if enc_flag: passphrase = None return _import_key_der(der, passphrase, None) if extern_key.startswith(b'ssh-dss '): # This is probably a public OpenSSH key keystring = binascii.a2b_base64(extern_key.split(b' ')[1]) keyparts = [] while len(keystring) > 4: length = struct.unpack(">I", keystring[:4])[0] keyparts.append(keystring[4:4 + length]) keystring = keystring[4 + length:] if keyparts[0] == b"ssh-dss": tup = [Integer.from_bytes(keyparts[x]) for x in (4, 3, 1, 2)] return construct(tup) if len(extern_key) > 0 and bord(extern_key[0]) == 0x30: # This is probably a DER encoded key return _import_key_der(extern_key, passphrase, None) raise ValueError("DSA key format is not supported")
def func(x): if (bord(x[0]) & 0x80): return bchr(0) + x else: return x
def import_key(extern_key, passphrase=None): """Import an RSA key (public or private). Args: extern_key (string or byte string): The RSA key to import. The following formats are supported for an RSA **public key**: - X.509 certificate (binary or PEM format) - X.509 ``subjectPublicKeyInfo`` DER SEQUENCE (binary or PEM encoding) - `PKCS#1`_ ``RSAPublicKey`` DER SEQUENCE (binary or PEM encoding) - An OpenSSH line (e.g. the content of ``~/.ssh/id_ecdsa``, ASCII) The following formats are supported for an RSA **private key**: - PKCS#1 ``RSAPrivateKey`` DER SEQUENCE (binary or PEM encoding) - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo`` DER SEQUENCE (binary or PEM encoding) - OpenSSH (text format, introduced in `OpenSSH 6.5`_) For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. passphrase (string or byte string): For private keys only, the pass phrase that encrypts the key. Returns: An RSA key object (:class:`RsaKey`). Raises: ValueError/IndexError/TypeError: When the given key cannot be parsed (possibly because the pass phrase is wrong). .. _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 .. _`OpenSSH 6.5`: https://flak.tedunangst.com/post/new-openssh-key-format-and-bcrypt-pbkdf """ from Crypto.IO import PEM extern_key = tobytes(extern_key) if passphrase is not None: passphrase = tobytes(passphrase) if extern_key.startswith(b'-----BEGIN OPENSSH PRIVATE KEY'): text_encoded = tostr(extern_key) openssh_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase) result = _import_openssh_private_rsa(openssh_encoded, passphrase) return result if extern_key.startswith(b'-----'): # This is probably a PEM encoded key. (der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase) if enc_flag: passphrase = None return _import_keyDER(der, passphrase) if extern_key.startswith(b'ssh-rsa '): # This is probably an OpenSSH key keystring = binascii.a2b_base64(extern_key.split(b' ')[1]) keyparts = [] while len(keystring) > 4: length = struct.unpack(">I", keystring[:4])[0] keyparts.append(keystring[4:4 + length]) keystring = keystring[4 + length:] e = Integer.from_bytes(keyparts[1]) n = Integer.from_bytes(keyparts[2]) return construct([n, e]) if len(extern_key) > 0 and bord(extern_key[0]) == 0x30: # This is probably a DER encoded key return _import_keyDER(extern_key, passphrase) raise ValueError("RSA key format is not supported")
def _double(self, bs): doubled = bytes_to_long(bs) << 1 if bord(bs[0]) & 0x80: doubled ^= 0x87 return long_to_bytes(doubled, len(bs))[-len(bs):]
def import_key(encoded, passphrase=None): """Import an ECC key (public or private). Args: encoded (bytes or multi-line string): The ECC key to import. An ECC **public** key can be: - An X.509 certificate, binary (DER) or ASCII (PEM) - An X.509 ``subjectPublicKeyInfo``, binary (DER) or ASCII (PEM) - An OpenSSH line (e.g. the content of ``~/.ssh/id_ecdsa``, ASCII) An ECC **private** key can be: - In binary format (DER, see section 3 of `RFC5915`_ or `PKCS#8`_) - In ASCII format (PEM or OpenSSH) Private keys can be in the clear or password-protected. For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. passphrase (byte string): The passphrase to use for decrypting a private key. Encryption may be applied protected at the PEM level or at the PKCS#8 level. This parameter is ignored if the key in input is not encrypted. Returns: :class:`EccKey` : a new ECC key object Raises: ValueError: when the given key cannot be parsed (possibly because the pass phrase is wrong). .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt .. _RFC5915: http://www.ietf.org/rfc/rfc5915.txt .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt """ encoded = tobytes(encoded) if passphrase is not None: passphrase = tobytes(passphrase) # PEM if encoded.startswith(b('-----')): der_encoded, marker, enc_flag = PEM.decode(tostr(encoded), passphrase) if enc_flag: passphrase = None try: result = _import_der(der_encoded, passphrase) except UnsupportedEccFeature as uef: raise uef except ValueError: raise ValueError("Invalid DER encoding inside the PEM file") return result # OpenSSH if encoded.startswith(b('ecdsa-sha2-')): return _import_openssh(encoded) # DER if bord(encoded[0]) == 0x30: return _import_der(encoded, passphrase) raise ValueError("ECC key format is not supported")
def _EMSA_PSS_VERIFY(mhash, em, emBits, mgf, sLen): """ Implement the ``EMSA-PSS-VERIFY`` function, as defined in PKCS#1 v2.1 (RFC3447, 9.1.2). ``EMSA-PSS-VERIFY`` actually accepts the message ``M`` as input, and hash it internally. Here, we expect that the message has already been hashed instead. :Parameters: mhash : hash object The hash object that holds the digest of the message to be verified. em : string The signature to verify, therefore proving that the sender really signed the message that was received. emBits : int Length of the final encoding (em), in bits. mgf : callable A mask generation function that accepts two parameters: a string to use as seed, and the lenth of the mask to generate, in bytes. sLen : int Length of the salt, in bytes. :Raise ValueError: When the encoding is inconsistent, or the digest or salt lengths are too big. """ emLen = ceil_div(emBits, 8) # Bitmask of digits that fill up lmask = 0 for i in iter_range(8 * emLen - emBits): lmask = lmask >> 1 | 0x80 # Step 1 and 2 have been already done # Step 3 if emLen < mhash.digest_size + sLen + 2: raise ValueError("Incorrect signature") # Step 4 if ord(em[-1:]) != 0xBC: raise ValueError("Incorrect signature") # Step 5 maskedDB = em[:emLen - mhash.digest_size - 1] h = em[emLen - mhash.digest_size - 1:-1] # Step 6 if lmask & bord(em[0]): raise ValueError("Incorrect signature") # Step 7 dbMask = mgf(h, emLen - mhash.digest_size - 1) # Step 8 db = strxor(maskedDB, dbMask) # Step 9 db = bchr(bord(db[0]) & ~lmask) + db[1:] # Step 10 if not db.startswith( bchr(0) * (emLen - mhash.digest_size - sLen - 2) + bchr(1)): raise ValueError("Incorrect signature") # Step 11 if sLen > 0: salt = db[-sLen:] else: salt = b"" # Step 12 m_prime = bchr(0) * 8 + mhash.digest() + salt # Step 13 hobj = mhash.new() hobj.update(m_prime) hp = hobj.digest() # Step 14 if h != hp: raise ValueError("Incorrect signature")
def _EMSA_PSS_ENCODE(mhash, emBits, randFunc, mgf, sLen): r""" Implement the ``EMSA-PSS-ENCODE`` function, as defined in PKCS#1 v2.1 (RFC3447, 9.1.1). The original ``EMSA-PSS-ENCODE`` actually accepts the message ``M`` as input, and hash it internally. Here, we expect that the message has already been hashed instead. :Parameters: mhash : hash object The hash object that holds the digest of the message being signed. emBits : int Maximum length of the final encoding, in bits. randFunc : callable An RNG function that accepts as only parameter an int, and returns a string of random bytes, to be used as salt. mgf : callable A mask generation function that accepts two parameters: a string to use as seed, and the lenth of the mask to generate, in bytes. sLen : int Length of the salt, in bytes. :Return: An ``emLen`` byte long string that encodes the hash (with ``emLen = \ceil(emBits/8)``). :Raise ValueError: When digest or salt length are too big. """ emLen = ceil_div(emBits, 8) # Bitmask of digits that fill up lmask = 0 for i in iter_range(8 * emLen - emBits): lmask = lmask >> 1 | 0x80 # Step 1 and 2 have been already done # Step 3 if emLen < mhash.digest_size + sLen + 2: raise ValueError("Digest or salt length are too long" " for given key size.") # Step 4 salt = randFunc(sLen) # Step 5 m_prime = bchr(0) * 8 + mhash.digest() + salt # Step 6 h = mhash.new() h.update(m_prime) # Step 7 ps = bchr(0) * (emLen - sLen - mhash.digest_size - 2) # Step 8 db = ps + bchr(1) + salt # Step 9 dbMask = mgf(h.digest(), emLen - mhash.digest_size - 1) # Step 10 maskedDB = strxor(db, dbMask) # Step 11 maskedDB = bchr(bord(maskedDB[0]) & ~lmask) + maskedDB[1:] # Step 12 em = maskedDB + h.digest() + bchr(0xBC) return em
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 = _copy_bytes(None, None, nonce) """Nonce used for this session.""" if len(nonce) not in range(1, 16): raise ValueError("Nonce must be at most 15 bytes long") if not is_buffer(nonce): raise TypeError("Nonce must be bytes, bytearray or memoryview") 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 = (struct.pack('B', self._mac_len << 4 & 0xFF) + b'\x00' * (14 - len(nonce)) + b'\x01' + self.nonce) bottom_bits = bord(nonce[15]) & 0x3F # 6 bits, 0..63 top_bits = bord(nonce[15]) & 0xC0 # 2 bits ktop_cipher = factory.new(key, factory.MODE_ECB, **params_without_key) ktop = ktop_cipher.encrypt(struct.pack('15sB', nonce[:15], top_bits)) stretch = ktop + strxor(ktop[:8], ktop[1:9]) # 192 bits offset_0 = long_to_bytes( bytes_to_long(stretch) >> (64 - bottom_bits), 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 import_key(encoded, passphrase=None): """Import an ECC key (public or private). Args: encoded (bytes or multi-line string): The ECC key to import. An ECC **public** key can be: - An X.509 certificate, binary (DER) or ASCII (PEM) - An X.509 ``subjectPublicKeyInfo``, binary (DER) or ASCII (PEM) - An OpenSSH line (e.g. the content of ``~/.ssh/id_ecdsa``, ASCII) An ECC **private** key can be: - In binary format (DER, see section 3 of `RFC5915`_ or `PKCS#8`_) - In ASCII format (PEM or `OpenSSH 6.5+`_) Private keys can be in the clear or password-protected. For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. passphrase (byte string): The passphrase to use for decrypting a private key. Encryption may be applied protected at the PEM level or at the PKCS#8 level. This parameter is ignored if the key in input is not encrypted. Returns: :class:`EccKey` : a new ECC key object Raises: ValueError: when the given key cannot be parsed (possibly because the pass phrase is wrong). .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt .. _RFC5915: http://www.ietf.org/rfc/rfc5915.txt .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt .. _`OpenSSH 6.5+`: https://flak.tedunangst.com/post/new-openssh-key-format-and-bcrypt-pbkdf """ from crypto.IO import PEM encoded = tobytes(encoded) if passphrase is not None: passphrase = tobytes(passphrase) # PEM if encoded.startswith(b'-----BEGIN OPENSSH PRIVATE KEY'): text_encoded = tostr(encoded) openssh_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase) result = _import_openssh_private_ecc(openssh_encoded, passphrase) return result elif encoded.startswith(b'-----'): text_encoded = tostr(encoded) # Remove any EC PARAMETERS section # Ignore its content because the curve type must be already given in the key if sys.version_info[:2] != (2, 6): ecparams_start = "-----BEGIN EC PARAMETERS-----" ecparams_end = "-----END EC PARAMETERS-----" text_encoded = re.sub(ecparams_start + ".*?" + ecparams_end, "", text_encoded, flags=re.DOTALL) der_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase) if enc_flag: passphrase = None try: result = _import_der(der_encoded, passphrase) except UnsupportedEccFeature as uef: raise uef except ValueError: raise ValueError("Invalid DER encoding inside the PEM file") return result # OpenSSH if encoded.startswith(b'ecdsa-sha2-'): return _import_openssh_public(encoded) # DER if len(encoded) > 0 and bord(encoded[0]) == 0x30: return _import_der(encoded, passphrase) raise ValueError("ECC key format is not supported")
def __init__(self, key, msg, ciphermod, cipher_params, mac_len): if ciphermod is None: raise TypeError("ciphermod must be specified (try AES)") self._key = _copy_bytes(None, None, key) self._factory = ciphermod if cipher_params is None: self._cipher_params = {} else: self._cipher_params = dict(cipher_params) self._mac_len = mac_len or ciphermod.block_size if self._mac_len < 4: raise ValueError("MAC tag length must be at least 4 bytes long") if self._mac_len > ciphermod.block_size: raise ValueError( "MAC tag length cannot be larger than a cipher block (%d) bytes" % ciphermod.block_size) # 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 = b'\x00' * 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 import_key(extern_key, passphrase=None): """Import an RSA key (public or private half), encoded in standard form. Args: extern_key (string or byte string): The RSA key to import. The following formats are supported for an RSA **public key**: - X.509 certificate (binary or PEM format) - X.509 ``subjectPublicKeyInfo`` DER SEQUENCE (binary or PEM encoding) - `PKCS#1`_ ``RSAPublicKey`` DER SEQUENCE (binary or PEM encoding) - OpenSSH (textual public key only) The following formats are supported for an RSA **private key**: - PKCS#1 ``RSAPrivateKey`` DER SEQUENCE (binary or PEM encoding) - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo`` DER SEQUENCE (binary or PEM encoding) - OpenSSH (textual public key only) For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. The private key may be encrypted by means of a certain pass phrase either at the PEM level or at the PKCS#8 level. passphrase (string): In case of an encrypted private key, this is the pass phrase from which the decryption key is derived. Returns: An RSA key object (:class:`RsaKey`). Raises: ValueError/IndexError/TypeError: When the given key cannot be parsed (possibly because the pass phrase is wrong). .. _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 """ extern_key = tobytes(extern_key) if passphrase is not None: passphrase = tobytes(passphrase) if extern_key.startswith(b('-----')): # This is probably a PEM encoded key. (der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase) if enc_flag: passphrase = None return _import_keyDER(der, passphrase) if extern_key.startswith(b('ssh-rsa ')): # This is probably an OpenSSH key keystring = binascii.a2b_base64(extern_key.split(b(' '))[1]) keyparts = [] while len(keystring) > 4: l = struct.unpack(">I", keystring[:4])[0] keyparts.append(keystring[4:4 + l]) keystring = keystring[4 + l:] e = Integer.from_bytes(keyparts[1]) n = Integer.from_bytes(keyparts[2]) return construct([n, e]) if bord(extern_key[0]) == 0x30: # This is probably a DER encoded key return _import_keyDER(extern_key, passphrase) raise ValueError("RSA key format is not supported")
def export_key(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 decrypt(self, ciphertext): """Decrypt a message with PKCS#1 OAEP. :param ciphertext: The encrypted message. :type ciphertext: bytes/bytearray/memoryview :returns: The original message (plaintext). :rtype: bytes :raises ValueError: if the ciphertext has the wrong length, or if decryption fails the integrity check (in which case, the decryption key is probably wrong). :raises TypeError: if the RSA key has no private half (i.e. you are trying to decrypt using a public key). """ # See 7.1.2 in RFC3447 modBits = crypto.Util.number.size(self._key.n) k = ceil_div(modBits, 8) # Convert from bits to bytes hLen = self._hashObj.digest_size # Step 1b and 1c if len(ciphertext) != k or k < hLen + 2: raise ValueError("Ciphertext with incorrect length.") # Step 2a (O2SIP) ct_int = bytes_to_long(ciphertext) # Step 2b (RSADP) m_int = self._key._decrypt(ct_int) # Complete step 2c (I2OSP) em = long_to_bytes(m_int, k) # Step 3a lHash = self._hashObj.new(self._label).digest() # Step 3b y = em[0] # y must be 0, but we MUST NOT check it here in order not to # allow attacks like Manger's (http://dl.acm.org/citation.cfm?id=704143) maskedSeed = em[1:hLen + 1] maskedDB = em[hLen + 1:] # Step 3c seedMask = self._mgf(maskedDB, hLen) # Step 3d seed = strxor(maskedSeed, seedMask) # Step 3e dbMask = self._mgf(seed, k - hLen - 1) # Step 3f db = strxor(maskedDB, dbMask) # Step 3g one_pos = db[hLen:].find(b'\x01') lHash1 = db[:hLen] invalid = bord(y) | int(one_pos < 0) hash_compare = strxor(lHash1, lHash) for x in hash_compare: invalid |= bord(x) for x in db[hLen:one_pos]: invalid |= bord(x) if invalid != 0: raise ValueError("Incorrect decryption.") # Step 4 return db[hLen + one_pos + 1:]
def read_byte(self): return bord(self.read(1)[0])