def __init__(self, keyDer = None): # TODO: Implementation of managed properties? if keyDer == None: self._keyDer = Blob() self._keyType = None return self._keyDer = keyDer # Get the public key OID. oidString = "" try: parsedNode = DerNode.parse(keyDer.buf(), 0) rootChildren = parsedNode.getChildren() algorithmIdChildren = DerNode.getSequence( rootChildren, 0).getChildren() oidString = algorithmIdChildren[0].toVal() except DerDecodingException as ex: raise UnrecognizedKeyFormatException( "PublicKey.decodeKeyType: Error decoding the public key" + str(ex)) # Verify that the we can decode. if oidString == self.RSA_ENCRYPTION_OID: self._keyType = KeyType.RSA RSA.importKey(keyDer.toRawStr()) elif oidString == self.EC_ENCRYPTION_OID: self._keyType = KeyType.ECDSA # TODO: Check EC decoding. else: raise UnrecognizedKeyFormatException( "PublicKey.decodeKeyType: Unrecognized OID " + oidString)
def __init__(self, keyDer=None): # TODO: Implementation of managed properties? if keyDer == None: self._keyDer = Blob() self._keyType = None return self._keyDer = keyDer # Get the public key OID. oidString = "" try: parsedNode = DerNode.parse(keyDer.buf(), 0) rootChildren = parsedNode.getChildren() algorithmIdChildren = DerNode.getSequence(rootChildren, 0).getChildren() oidString = algorithmIdChildren[0].toVal() except DerDecodingException as ex: raise UnrecognizedKeyFormatException( "PublicKey.decodeKeyType: Error decoding the public key: " + str(ex)) # Verify that the we can decode. if oidString == self.RSA_ENCRYPTION_OID: self._keyType = KeyType.RSA serialization.load_der_public_key(keyDer.toBytes(), backend=default_backend()) elif oidString == self.EC_ENCRYPTION_OID: self._keyType = KeyType.ECDSA # TODO: Check EC decoding. else: raise UnrecognizedKeyFormatException( "PublicKey.decodeKeyType: Unrecognized OID " + oidString)
def sign(self, data, keyName, digestAlgorithm=DigestAlgorithm.SHA256): """ Fetch the private key for keyName and sign the data, returning a signature Blob. :param data: Pointer the input byte buffer to sign. :type data: An array type with int elements :param Name keyName: The name of the signing key. :param digestAlgorithm: (optional) the digest algorithm. If omitted, use DigestAlgorithm.SHA256. :type digestAlgorithm: int from DigestAlgorithm :return: The signature Blob. :rtype: Blob """ keyURI = keyName.toUri() if not self.doesKeyExist(keyName, KeyClass.PRIVATE): raise SecurityException( "FilePrivateKeyStorage.sign: private key doesn't exist") if digestAlgorithm != DigestAlgorithm.SHA256: raise SecurityException( "FilePrivateKeyStorage.sign: Unsupported digest algorithm") # Read the private key. base64Content = None with open(self.nameTransform(keyURI, ".pri")) as keyFile: base64Content = keyFile.read() der = Blob(base64.b64decode(base64Content), False) # Decode the PKCS #8 key to get the algorithm OID. parsedNode = DerNode.parse(der.buf(), 0) pkcs8Children = parsedNode.getChildren() algorithmIdChildren = DerNode.getSequence(pkcs8Children, 1).getChildren() oidString = algorithmIdChildren[0].toVal() privateKey = serialization.load_der_private_key( der.toBytes(), password=None, backend=default_backend()) # Sign the data. data = Blob(data, False).toBytes() if (oidString == PublicKey.RSA_ENCRYPTION_OID or oidString == PublicKey.EC_ENCRYPTION_OID): if oidString == PublicKey.RSA_ENCRYPTION_OID: signer = privateKey.signer(padding.PKCS1v15(), hashes.SHA256()) else: signer = privateKey.signer(ec.ECDSA(hashes.SHA256())) signer.update(data) signature = signer.finalize() return Blob(bytearray(signature), False) else: raise SecurityException( "FilePrivateKeyStorage.sign: Unrecognized private key type")
def sign(self, data, keyName, digestAlgorithm = DigestAlgorithm.SHA256): """ Fetch the private key for keyName and sign the data, returning a signature Blob. :param data: Pointer the input byte buffer to sign. :type data: An array type with int elements :param Name keyName: The name of the signing key. :param digestAlgorithm: (optional) the digest algorithm. If omitted, use DigestAlgorithm.SHA256. :type digestAlgorithm: int from DigestAlgorithm :return: The signature Blob. :rtype: Blob """ keyURI = keyName.toUri() if not self.doesKeyExist(keyName, KeyClass.PRIVATE): raise SecurityException( "FilePrivateKeyStorage.sign: private key doesn't exist") if digestAlgorithm != DigestAlgorithm.SHA256: raise SecurityException( "FilePrivateKeyStorage.sign: Unsupported digest algorithm") # Read the private key. base64Content = None with open(self.nameTransform(keyURI, ".pri")) as keyFile: base64Content = keyFile.read() der = Blob(base64.b64decode(base64Content), False) # Decode the PKCS #8 key to get the algorithm OID. parsedNode = DerNode.parse(der.buf(), 0) pkcs8Children = parsedNode.getChildren() algorithmIdChildren = DerNode.getSequence(pkcs8Children, 1).getChildren() oidString = algorithmIdChildren[0].toVal() privateKey = serialization.load_der_private_key( der.toBytes(), password = None, backend = default_backend()) # Sign the data. data = Blob(data, False).toBytes() if (oidString == PublicKey.RSA_ENCRYPTION_OID or oidString == PublicKey.EC_ENCRYPTION_OID): if oidString == PublicKey.RSA_ENCRYPTION_OID: signer = privateKey.signer(padding.PKCS1v15(), hashes.SHA256()) else: signer = privateKey.signer(ec.ECDSA(hashes.SHA256())) signer.update(data) signature = signer.finalize() return Blob(bytearray(signature), False) else: raise SecurityException( "FilePrivateKeyStorage.sign: Unrecognized private key type")
def toDer(self): """ Encode the public key into DER. :return: The encoded DER syntax tree. :rtype: DerNode """ return DerNode.parse(self._keyDer)
def loadPkcs8(self, encoding, keyType=None): """ Load the unencrypted private key from a buffer with the PKCS #8 encoding. This replaces any existing private key in this object. :param encoding: The byte buffer with the private key encoding. :type encoding: str, or an array type with int elements which is converted to str :param KeyType keyType: (optional) The KeyType, such as KeyType.RSA. If omitted or None, then partially decode the private key to determine the key type. :raises TpmPrivateKey.Error: For errors decoding the key. """ if keyType == None: # Decode the PKCS #8 DER to find the algorithm OID. oidString = None try: parsedNode = DerNode.parse(Blob(encoding, False).buf()) pkcs8Children = parsedNode.getChildren() algorithmIdChildren = DerNode.getSequence(pkcs8Children, 1).getChildren() oidString = "" + algorithmIdChildren[0].toVal() except Exception as ex: raise TpmPrivateKey.Error( "Cannot decode the PKCS #8 private key: " + str(ex)) if oidString == TpmPrivateKey.EC_ENCRYPTION_OID: keyType = KeyType.ECDSA elif oidString == TpmPrivateKey.RSA_ENCRYPTION_OID: keyType = KeyType.RSA else: raise TpmPrivateKey.Error( "loadPkcs8: Unrecognized private key OID: " + oidString) if keyType == KeyType.ECDSA or keyType == KeyType.RSA: self._privateKey = serialization.load_der_private_key( Blob(encoding, False).toBytes(), password=None, backend=default_backend()) else: raise TpmPrivateKey.Error("loadPkcs8: Unrecognized keyType: " + str(keyType)) self._keyType = keyType
def loadPkcs8(self, encoding, keyType = None): """ Load the unencrypted private key from a buffer with the PKCS #8 encoding. This replaces any existing private key in this object. :param encoding: The byte buffer with the private key encoding. :type encoding: str, or an array type with int elements which is converted to str :param KeyType keyType: (optional) The KeyType, such as KeyType.RSA. If omitted or None, then partially decode the private key to determine the key type. :raises TpmPrivateKey.Error: For errors decoding the key. """ if keyType == None: # Decode the PKCS #8 DER to find the algorithm OID. oidString = None try: parsedNode = DerNode.parse(Blob(encoding, False).buf()) pkcs8Children = parsedNode.getChildren() algorithmIdChildren = DerNode.getSequence( pkcs8Children, 1).getChildren() oidString = "" + algorithmIdChildren[0].toVal() except Exception as ex: raise TpmPrivateKey.Error( "Cannot decode the PKCS #8 private key: " + str(ex)) if oidString == TpmPrivateKey.EC_ENCRYPTION_OID: keyType = KeyType.EC elif oidString == TpmPrivateKey.RSA_ENCRYPTION_OID: keyType = KeyType.RSA else: raise TpmPrivateKey.Error( "loadPkcs8: Unrecognized private key OID: " + oidString) if keyType == KeyType.EC or keyType == KeyType.RSA: self._privateKey = serialization.load_der_private_key( Blob(encoding, False).toBytes(), password = None, backend = default_backend()) else: raise TpmPrivateKey.Error( "loadPkcs8: Unrecognized keyType: " + str(keyType)) self._keyType = keyType
def loadPkcs1(self, encoding, keyType=None): """ Load the unencrypted private key from a buffer with the PKCS #1 encoding. This replaces any existing private key in this object. :param encoding: The byte buffer with the private key encoding. :type encoding: str, or an array type with int elements which is converted to str :param KeyType keyType: (optional) The KeyType, such as KeyType.RSA. If omitted or None, then partially decode the private key to determine the key type. :raises TpmPrivateKey.Error: For errors decoding the key. """ if keyType == None: # Try to determine the key type. try: parsedNode = DerNode.parse(Blob(encoding, False).buf()) children = parsedNode.getChildren() # An RsaPrivateKey has integer version 0 and 8 integers. if (len(children) == 9 and isinstance(children[0], DerInteger) and children[0].toVal() == 0 and isinstance(children[1], DerInteger) and isinstance(children[2], DerInteger) and isinstance(children[3], DerInteger) and isinstance(children[4], DerInteger) and isinstance(children[5], DerInteger) and isinstance(children[6], DerInteger) and isinstance(children[7], DerInteger) and isinstance(children[8], DerInteger)): keyType = KeyType.RSA else: # Assume it is an EC key. Try decoding it below. keyType = KeyType.ECDSA except DerDecodingException: # Assume it is an EC key. Try decoding it below. keyType = KeyType.ECDSA if keyType == KeyType.ECDSA or keyType == KeyType.RSA: # serialization can load PKCS #1 directly. self._privateKey = serialization.load_der_private_key( Blob(encoding, False).toBytes(), password=None, backend=default_backend()) else: raise TpmPrivateKey.Error("loadPkcs1: Unrecognized keyType: " + str(keyType)) self._keyType = keyType
def loadPkcs1(self, encoding, keyType = None): """ Load the unencrypted private key from a buffer with the PKCS #1 encoding. This replaces any existing private key in this object. :param encoding: The byte buffer with the private key encoding. :type encoding: str, or an array type with int elements which is converted to str :param KeyType keyType: (optional) The KeyType, such as KeyType.RSA. If omitted or None, then partially decode the private key to determine the key type. :raises TpmPrivateKey.Error: For errors decoding the key. """ if keyType == None: # Try to determine the key type. try: parsedNode = DerNode.parse(Blob(encoding, False).buf()) children = parsedNode.getChildren() # An RsaPrivateKey has integer version 0 and 8 integers. if (len(children) == 9 and isinstance(children[0], DerInteger) and children[0].toVal() == 0 and isinstance(children[1], DerInteger) and isinstance(children[2], DerInteger) and isinstance(children[3], DerInteger) and isinstance(children[4], DerInteger) and isinstance(children[5], DerInteger) and isinstance(children[6], DerInteger) and isinstance(children[7], DerInteger) and isinstance( children[8], DerInteger)): keyType = KeyType.RSA else: # Assume it is an EC key. Try decoding it below. keyType = KeyType.EC except DerDecodingException: # Assume it is an EC key. Try decoding it below. keyType = KeyType.EC if keyType == KeyType.EC or keyType == KeyType.RSA: # serialization can load PKCS #1 directly. self._privateKey = serialization.load_der_private_key( Blob(encoding, False).toBytes(), password = None, backend = default_backend()) else: raise TpmPrivateKey.Error( "loadPkcs1: Unrecognized keyType: " + str(keyType)) self._keyType = keyType
def toPkcs1(self): """ Get the encoded unencrypted private key in PKCS #1. :return: The private key encoding Blob. :rtype: Blob :raises TpmPrivateKey.Error: If no private key is loaded, or error encoding. """ if self._keyType == None: raise TpmPrivateKey.Error("toPkcs1: The private key is not loaded") # Decode the PKCS #8 private key. try: parsedNode = DerNode.parse(self.toPkcs8().buf(), 0) pkcs8Children = parsedNode.getChildren() return pkcs8Children[2].getPayload() except Exception as ex: raise TpmPrivateKey.Error( "Error decoding PKCS #8 private key: " + str(ex))
def toPkcs1(self): """ Get the encoded unencrypted private key in PKCS #1. :return: The private key encoding Blob. :rtype: Blob :raises TpmPrivateKey.Error: If no private key is loaded, or error encoding. """ if self._keyType == None: raise TpmPrivateKey.Error("toPkcs1: The private key is not loaded") # Decode the PKCS #8 private key. try: parsedNode = DerNode.parse(self.toPkcs8().buf(), 0) pkcs8Children = parsedNode.getChildren() return pkcs8Children[2].getPayload() except Exception as ex: raise TpmPrivateKey.Error("Error decoding PKCS #8 private key: " + str(ex))
def loadEncryptedPkcs8(self, encoding, password): """ Load the encrypted private key from a buffer with the PKCS #8 encoding of the EncryptedPrivateKeyInfo. This replaces any existing private key in this object. This partially decodes the private key to determine the key type. :param encoding: The byte buffer with the private key encoding. :type encoding: str, or an array type with int elements which is converted to str :param password: The password for decrypting the private key, which should have characters in the range of 1 to 127.. :type password: an array which implements the buffer protocol :raises TpmPrivateKey.Error: For errors decoding the key. """ # Decode the PKCS #8 EncryptedPrivateKeyInfo. # See https://tools.ietf.org/html/rfc5208. oidString = None parameters = None encryptedKey = None try: parsedNode = DerNode.parse(Blob(encoding, False).buf()) encryptedPkcs8Children = parsedNode.getChildren() algorithmIdChildren = DerNode.getSequence( encryptedPkcs8Children, 0).getChildren() oidString = algorithmIdChildren[0].toVal() parameters = algorithmIdChildren[1] encryptedKey = encryptedPkcs8Children[1].toVal() except Exception as ex: raise TpmPrivateKey.Error( "Cannot decode the PKCS #8 EncryptedPrivateKeyInfo: " + str(ex)) if oidString == TpmPrivateKey.PBES2_OID: # Decode the PBES2 parameters. See https://www.ietf.org/rfc/rfc2898.txt . keyDerivationOidString = None keyDerivationParameters = None encryptionSchemeOidString = None encryptionSchemeParameters = None try: parametersChildren = parameters.getChildren() keyDerivationAlgorithmIdChildren = DerNode.getSequence( parametersChildren, 0).getChildren() keyDerivationOidString = keyDerivationAlgorithmIdChildren[0].toVal() keyDerivationParameters = keyDerivationAlgorithmIdChildren[1] encryptionSchemeAlgorithmIdChildren = DerNode.getSequence( parametersChildren, 1).getChildren() encryptionSchemeOidString = encryptionSchemeAlgorithmIdChildren[0].toVal() encryptionSchemeParameters = encryptionSchemeAlgorithmIdChildren[1] except Exception as ex: raise TpmPrivateKey.Error( "Cannot decode the PBES2 parameters: " + str(ex)) # Get the derived key from the password. derivedKey = None if keyDerivationOidString == TpmPrivateKey.PBKDF2_OID: # Decode the PBKDF2 parameters. salt = None nIterations = None try: pbkdf2ParametersChildren = keyDerivationParameters.getChildren() salt = pbkdf2ParametersChildren[0].toVal() nIterations = pbkdf2ParametersChildren[1].toVal() except Exception as ex: raise TpmPrivateKey.Error( "Cannot decode the PBES2 parameters: " + str(ex)) # Check the encryption scheme here to get the needed result length. resultLength = None if encryptionSchemeOidString == TpmPrivateKey.DES_EDE3_CBC_OID: resultLength = TpmPrivateKey.DES_EDE3_KEY_LENGTH else: raise TpmPrivateKey.Error( "Unrecognized PBES2 encryption scheme OID: " + encryptionSchemeOidString) else: raise TpmPrivateKey.Error( "Unrecognized PBES2 key derivation OID: " + keyDerivationOidString) pbkdf2 = PBKDF2HMAC(algorithm = hashes.SHA1(), length = resultLength, salt = Blob(salt, False).toBytes(), iterations = nIterations, backend = default_backend()) derivedKey = pbkdf2.derive(Blob(password, False).toBytes()) # Use the derived key to get the unencrypted pkcs8Encoding. if encryptionSchemeOidString == TpmPrivateKey.DES_EDE3_CBC_OID: # Decode the DES-EDE3-CBC parameters. initialVector = None try: initialVector = encryptionSchemeParameters.toVal() except Exception as ex: raise TpmPrivateKey.Error( "Cannot decode the DES-EDE3-CBC parameters: " + str(ex)) try: cipher = Cipher(algorithms.TripleDES( Blob(derivedKey, False).toBytes()), modes.CBC(Blob(initialVector, False).toBytes()), backend = default_backend()) # For the cryptography package, we have to remove the padding. decryptor = cipher.decryptor() resultWithPad = decryptor.update( Blob(encryptedKey, False).toBytes()) + decryptor.finalize() if sys.version_info[0] <= 2: padLength = ord(resultWithPad[-1]) else: padLength = resultWithPad[-1] pkcs8Encoding = resultWithPad[:-padLength] except Exception as ex: raise TpmPrivateKey.Error( "Error decrypting the PKCS #8 key with DES-EDE3-CBC: " + str(ex)) else: raise TpmPrivateKey.Error( "Unrecognized PBES2 encryption scheme OID: " + encryptionSchemeOidString) else: raise TpmPrivateKey.Error( "Unrecognized PKCS #8 EncryptedPrivateKeyInfo OID: " + oidString) self.loadPkcs8(pkcs8Encoding)
def loadEncryptedPkcs8(self, encoding, password): """ Load the encrypted private key from a buffer with the PKCS #8 encoding of the EncryptedPrivateKeyInfo. This replaces any existing private key in this object. This partially decodes the private key to determine the key type. :param encoding: The byte buffer with the private key encoding. :type encoding: str, or an array type with int elements which is converted to str :param password: The password for decrypting the private key, which should have characters in the range of 1 to 127.. :type password: an array which implements the buffer protocol :raises TpmPrivateKey.Error: For errors decoding the key. """ # Decode the PKCS #8 EncryptedPrivateKeyInfo. # See https://tools.ietf.org/html/rfc5208. oidString = None parameters = None encryptedKey = None try: parsedNode = DerNode.parse(Blob(encoding, False).buf()) encryptedPkcs8Children = parsedNode.getChildren() algorithmIdChildren = DerNode.getSequence(encryptedPkcs8Children, 0).getChildren() oidString = algorithmIdChildren[0].toVal() parameters = algorithmIdChildren[1] encryptedKey = encryptedPkcs8Children[1].toVal() except Exception as ex: raise TpmPrivateKey.Error( "Cannot decode the PKCS #8 EncryptedPrivateKeyInfo: " + str(ex)) if oidString == TpmPrivateKey.PBES2_OID: # Decode the PBES2 parameters. See https://www.ietf.org/rfc/rfc2898.txt . keyDerivationOidString = None keyDerivationParameters = None encryptionSchemeOidString = None encryptionSchemeParameters = None try: parametersChildren = parameters.getChildren() keyDerivationAlgorithmIdChildren = DerNode.getSequence( parametersChildren, 0).getChildren() keyDerivationOidString = keyDerivationAlgorithmIdChildren[ 0].toVal() keyDerivationParameters = keyDerivationAlgorithmIdChildren[1] encryptionSchemeAlgorithmIdChildren = DerNode.getSequence( parametersChildren, 1).getChildren() encryptionSchemeOidString = encryptionSchemeAlgorithmIdChildren[ 0].toVal() encryptionSchemeParameters = encryptionSchemeAlgorithmIdChildren[ 1] except Exception as ex: raise TpmPrivateKey.Error( "Cannot decode the PBES2 parameters: " + str(ex)) # Get the derived key from the password. derivedKey = None if keyDerivationOidString == TpmPrivateKey.PBKDF2_OID: # Decode the PBKDF2 parameters. salt = None nIterations = None try: pbkdf2ParametersChildren = keyDerivationParameters.getChildren( ) salt = pbkdf2ParametersChildren[0].toVal() nIterations = pbkdf2ParametersChildren[1].toVal() except Exception as ex: raise TpmPrivateKey.Error( "Cannot decode the PBES2 parameters: " + str(ex)) # Check the encryption scheme here to get the needed result length. resultLength = None if encryptionSchemeOidString == TpmPrivateKey.DES_EDE3_CBC_OID: resultLength = TpmPrivateKey.DES_EDE3_KEY_LENGTH else: raise TpmPrivateKey.Error( "Unrecognized PBES2 encryption scheme OID: " + encryptionSchemeOidString) else: raise TpmPrivateKey.Error( "Unrecognized PBES2 key derivation OID: " + keyDerivationOidString) pbkdf2 = PBKDF2HMAC(algorithm=hashes.SHA1(), length=resultLength, salt=Blob(salt, False).toBytes(), iterations=nIterations, backend=default_backend()) derivedKey = pbkdf2.derive(Blob(password, False).toBytes()) # Use the derived key to get the unencrypted pkcs8Encoding. if encryptionSchemeOidString == TpmPrivateKey.DES_EDE3_CBC_OID: # Decode the DES-EDE3-CBC parameters. initialVector = None try: initialVector = encryptionSchemeParameters.toVal() except Exception as ex: raise TpmPrivateKey.Error( "Cannot decode the DES-EDE3-CBC parameters: " + str(ex)) try: cipher = Cipher(algorithms.TripleDES( Blob(derivedKey, False).toBytes()), modes.CBC( Blob(initialVector, False).toBytes()), backend=default_backend()) # For the cryptography package, we have to remove the padding. decryptor = cipher.decryptor() resultWithPad = decryptor.update( Blob(encryptedKey, False).toBytes()) + decryptor.finalize() if sys.version_info[0] <= 2: padLength = ord(resultWithPad[-1]) else: padLength = resultWithPad[-1] pkcs8Encoding = resultWithPad[:-padLength] except Exception as ex: raise TpmPrivateKey.Error( "Error decrypting the PKCS #8 key with DES-EDE3-CBC: " + str(ex)) else: raise TpmPrivateKey.Error( "Unrecognized PBES2 encryption scheme OID: " + encryptionSchemeOidString) else: raise TpmPrivateKey.Error( "Unrecognized PKCS #8 EncryptedPrivateKeyInfo OID: " + oidString) self.loadPkcs8(pkcs8Encoding)