Skip to content

Commit

Permalink
Add decryption of AES-encrypted keys
Browse files Browse the repository at this point in the history
  • Loading branch information
jrclark2 committed Dec 31, 2019
1 parent ac49f5d commit acf5d1b
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 155 deletions.
5 changes: 5 additions & 0 deletions pom-android-with-async-io.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.madgag.spongycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.58.0.0</version>
</dependency>
</dependencies>
<distributionManagement>
<snapshotRepository>
Expand Down
5 changes: 5 additions & 0 deletions pom-android.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.madgag.spongycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.58.0.0</version>
</dependency>
</dependencies>
<distributionManagement>
<snapshotRepository>
Expand Down
5 changes: 5 additions & 0 deletions pom-without-protobuf.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.madgag.spongycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.58.0.0</version>
</dependency>
</dependencies>
<distributionManagement>
<snapshotRepository>
Expand Down
13 changes: 13 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.madgag.spongycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.58.0.0</version>
</dependency>
</dependencies>
<distributionManagement>
<snapshotRepository>
Expand All @@ -66,6 +71,14 @@
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
Expand Down
4 changes: 2 additions & 2 deletions src/net/named_data/jndn/security/tpm/TpmBackEndFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ public TpmBackEndFile(String locationPath)
byte[] pkcs = Common.base64Decode(base64.toString());

try {
key.loadPkcs1(ByteBuffer.wrap(pkcs), null);
key.loadPkcs8(ByteBuffer.wrap(pkcs));
} catch (TpmPrivateKey.Error ex) {
throw new TpmBackEnd.Error("Error decoding private key file: " + ex);
}
Expand All @@ -298,7 +298,7 @@ public TpmBackEndFile(String locationPath)
String filePath = toFilePath(keyName).getAbsolutePath();
String base64;
try {
base64 = Common.base64Encode(key.toPkcs1().getImmutableArray(), true);
base64 = Common.base64Encode(key.toPkcs8().getImmutableArray(), true);
} catch (TpmPrivateKey.Error ex) {
throw new TpmBackEnd.Error("Error encoding private key file: " + ex);
}
Expand Down
210 changes: 62 additions & 148 deletions src/net/named_data/jndn/security/tpm/TpmPrivateKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,21 @@

package net.named_data.jndn.security.tpm;

import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.KeyPairGenerator;
import java.security.KeyPair;
import java.security.Security;
import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
Expand All @@ -48,12 +52,24 @@
import net.named_data.jndn.security.RsaKeyParams;
import net.named_data.jndn.util.Blob;
import net.named_data.jndn.util.Common;
import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
import org.spongycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.spongycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
import org.spongycastle.operator.InputDecryptorProvider;
import org.spongycastle.operator.OperatorCreationException;
import org.spongycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.spongycastle.pkcs.PKCSException;


/**
* A TpmPrivateKey holds an in-memory private key and provides cryptographic
* operations such as for signing by the in-memory TPM.
*/
public class TpmPrivateKey {
static {
Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
}

/**
* A TpmPrivateKey.Error extends Exception and represents an error in private
* key processing.
Expand Down Expand Up @@ -127,6 +143,48 @@ else if (keyType == KeyType.RSA)
loadPkcs8(pkcs8.buf(), keyType);
}

/**
* 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.
* @param encoding The byte buffer with the private key encoding.
* @param password The password for decrypting the private key, which should
* have characters in the range of 1 to 127.
* @throws TpmPrivateKey.Error for errors decoding or decrypting the key.
*/
public final void
loadEncryptedPkcs8
(ByteBuffer encoding, ByteBuffer password) throws TpmPrivateKey.Error {
//BouncyCastle classes expect a byte array and char array
byte[] encodingBytes = new byte[10];
encodingBytes = new byte[encoding.capacity()];
encoding.get(encodingBytes, 0, encodingBytes.length);
encoding.clear();

CharBuffer charBuffer = Charset.forName("ISO-8859-1").decode(password);
char[] passwordBytes = charBuffer.array();

try {
PKCS8EncryptedPrivateKeyInfo privateKeyInfo = new PKCS8EncryptedPrivateKeyInfo(encodingBytes);
JceOpenSSLPKCS8DecryptorProviderBuilder jce = new JceOpenSSLPKCS8DecryptorProviderBuilder();
jce.setProvider("SC");
InputDecryptorProvider decProv = jce.build(passwordBytes);
PrivateKeyInfo info = privateKeyInfo.decryptPrivateKeyInfo(decProv);
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
privateKey_ = converter.getPrivateKey(info);
String keyTypeString = privateKey_.getAlgorithm();
if (keyTypeString.equals("RSA")) keyType_ = KeyType.RSA;
else if (keyTypeString.equals("ECDSA")) keyType_= KeyType.EC;
else throw new TpmPrivateKey.Error
("loadEncryptedPkcs8: Key type " + keyTypeString + " not supported");

} catch (IOException | OperatorCreationException | PKCSException ex) {
throw new TpmPrivateKey.Error
("loadEncryptedPkcs8: Error parsing PrivateKey info: " + ex);
}

}

/**
* Load the unencrypted private key from a buffer with the PKCS #1 encoding.
* This replaces any existing private key in this object. This partially
Expand Down Expand Up @@ -228,149 +286,6 @@ else if (keyType == KeyType.RSA) {
loadPkcs8(encoding, null);
}

/**
* 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.
* @param password The password for decrypting the private key, which should
* have characters in the range of 1 to 127.
* @throws TpmPrivateKey.Error for errors decoding or decrypting the key.
*/
public final void
loadEncryptedPkcs8(ByteBuffer encoding, ByteBuffer password)
throws TpmPrivateKey.Error
{
// Decode the PKCS #8 EncryptedPrivateKeyInfo.
// See https://tools.ietf.org/html/rfc5208.
String oidString;
Object parameters;
Blob encryptedKey;
try {
DerNode parsedNode = DerNode.parse(encoding, 0);
List encryptedPkcs8Children = parsedNode.getChildren();
List algorithmIdChildren = DerNode.getSequence
(encryptedPkcs8Children, 0).getChildren();
oidString = "" + ((DerNode.DerOid)algorithmIdChildren.get(0)).toVal();
parameters = algorithmIdChildren.get(1);

encryptedKey =
(Blob)((DerNode.DerOctetString)encryptedPkcs8Children.get(1)).toVal();
}
catch (Throwable ex) {
throw new TpmPrivateKey.Error
("Cannot decode the PKCS #8 EncryptedPrivateKeyInfo: " + ex);
}

// Use the password to get the unencrypted pkcs8Encoding.
byte[] pkcs8Encoding;
if (oidString.equals(PBES2_OID)) {
// Decode the PBES2 parameters. See https://www.ietf.org/rfc/rfc2898.txt .
String keyDerivationOidString;
Object keyDerivationParameters;
String encryptionSchemeOidString;
Object encryptionSchemeParameters;
try {
List parametersChildren = ((DerNode.DerSequence)parameters).getChildren();

List keyDerivationAlgorithmIdChildren = DerNode.getSequence
(parametersChildren, 0).getChildren();
keyDerivationOidString = "" +
((DerNode.DerOid)keyDerivationAlgorithmIdChildren.get(0)).toVal();
keyDerivationParameters = keyDerivationAlgorithmIdChildren.get(1);

List encryptionSchemeAlgorithmIdChildren = DerNode.getSequence
(parametersChildren, 1).getChildren();
encryptionSchemeOidString = "" +
((DerNode.DerOid)encryptionSchemeAlgorithmIdChildren.get(0)).toVal();
encryptionSchemeParameters = encryptionSchemeAlgorithmIdChildren.get(1);
}
catch (Throwable ex) {
throw new TpmPrivateKey.Error
("Cannot decode the PBES2 parameters: " + ex);
}

// Get the derived key from the password.
byte[] derivedKey = null;
if (keyDerivationOidString.equals(PBKDF2_OID)) {
// Decode the PBKDF2 parameters.
Blob salt;
int nIterations;
try {
List pbkdf2ParametersChildren =
((DerNode.DerSequence)keyDerivationParameters).getChildren();
salt = (Blob)
((DerNode.DerOctetString)pbkdf2ParametersChildren.get(0)).toVal();
nIterations = (int)
((DerNode.DerInteger)pbkdf2ParametersChildren.get(1)).toVal();
}
catch (Throwable ex) {
throw new TpmPrivateKey.Error
("Cannot decode the PBES2 parameters: " + ex);
}

// Check the encryption scheme here to get the needed result length.
int resultLength;
if (encryptionSchemeOidString.equals(DES_EDE3_CBC_OID))
resultLength = DES_EDE3_KEY_LENGTH;
else
throw new TpmPrivateKey.Error
("Unrecognized PBES2 encryption scheme OID: " +
encryptionSchemeOidString);

try {
derivedKey = Common.computePbkdf2WithHmacSha1
(new Blob(password, false).getImmutableArray(),
salt.getImmutableArray(), nIterations, resultLength);
}
catch (Throwable ex) {
throw new TpmPrivateKey.Error
("Error computing the derived key using PBKDF2 with HMAC SHA1: " + ex);
}
}
else
throw new TpmPrivateKey.Error
("Unrecognized PBES2 key derivation OID: " + keyDerivationOidString);

// Use the derived key to get the unencrypted pkcs8Encoding.
if (encryptionSchemeOidString.equals(DES_EDE3_CBC_OID)) {
// Decode the DES-EDE3-CBC parameters.
Blob initialVector;
try {
initialVector = (Blob)
((DerNode.DerOctetString)encryptionSchemeParameters).toVal();
}
catch (Throwable ex) {
throw new TpmPrivateKey.Error
("Cannot decode the DES-EDE3-CBC parameters: " + ex);
}

try {
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init
(Cipher.DECRYPT_MODE,
new SecretKeySpec(derivedKey, "DESede"),
new IvParameterSpec(initialVector.getImmutableArray()));
pkcs8Encoding = cipher.doFinal(encryptedKey.getImmutableArray());
}
catch (Throwable ex) {
throw new TpmPrivateKey.Error
("Error decrypting PKCS #8 key with DES-EDE3-CBC: " + ex);
}
}
else
throw new TpmPrivateKey.Error
("Unrecognized PBES2 encryption scheme OID: " +
encryptionSchemeOidString);
}
else
throw new TpmPrivateKey.Error
("Unrecognized PKCS #8 EncryptedPrivateKeyInfo OID: " + oidString);

loadPkcs8(ByteBuffer.wrap(pkcs8Encoding));
}

/**
* Get the encoded public key for this private key.
* @return The public key encoding Blob.
Expand Down Expand Up @@ -554,8 +469,7 @@ else if (keyType_ == KeyType.RSA) {

/**
* Get the encoded encrypted private key in PKCS #8.
* @param password The password for encrypting the private key, which should
* have characters in the range of 1 to 127.
* @param password The password for encrypting the private key.
* @return The encoding Blob of the EncryptedPrivateKeyInfo.
* @throws TpmPrivateKey.Error if no private key is loaded, or error encoding.
*/
Expand Down Expand Up @@ -692,7 +606,7 @@ else if (keyParams.getKeyType() == KeyType.EC) {
*/
private static Blob
encodePkcs8PrivateKey(ByteBuffer privateKeyDer, OID oid, DerNode parameters)
throws TpmPrivateKey.Error
throws TpmPrivateKey.Error
{
try {
DerSequence algorithmIdentifier = new DerSequence();
Expand Down
Loading

0 comments on commit acf5d1b

Please sign in to comment.