diff --git a/pom-android-with-async-io.xml b/pom-android-with-async-io.xml
index 157d5976..71cee258 100644
--- a/pom-android-with-async-io.xml
+++ b/pom-android-with-async-io.xml
@@ -43,6 +43,11 @@
4.10
test
+
+ com.madgag.spongycastle
+ bcpkix-jdk15on
+ 1.58.0.0
+
diff --git a/pom-android.xml b/pom-android.xml
index 332a0918..b524a9fc 100644
--- a/pom-android.xml
+++ b/pom-android.xml
@@ -43,6 +43,11 @@
4.10
test
+
+ com.madgag.spongycastle
+ bcpkix-jdk15on
+ 1.58.0.0
+
diff --git a/pom-without-protobuf.xml b/pom-without-protobuf.xml
index f9035b59..432ec4d3 100644
--- a/pom-without-protobuf.xml
+++ b/pom-without-protobuf.xml
@@ -43,6 +43,11 @@
4.10
test
+
+ com.madgag.spongycastle
+ bcpkix-jdk15on
+ 1.58.0.0
+
diff --git a/pom.xml b/pom.xml
index 3eba8492..e2808934 100644
--- a/pom.xml
+++ b/pom.xml
@@ -44,6 +44,11 @@
4.10
test
+
+ com.madgag.spongycastle
+ bcpkix-jdk15on
+ 1.58.0.0
+
@@ -66,6 +71,14 @@
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 9
+
+
diff --git a/src/net/named_data/jndn/security/tpm/TpmBackEndFile.java b/src/net/named_data/jndn/security/tpm/TpmBackEndFile.java
index c29c4869..fc583f82 100644
--- a/src/net/named_data/jndn/security/tpm/TpmBackEndFile.java
+++ b/src/net/named_data/jndn/security/tpm/TpmBackEndFile.java
@@ -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);
}
@@ -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);
}
diff --git a/src/net/named_data/jndn/security/tpm/TpmPrivateKey.java b/src/net/named_data/jndn/security/tpm/TpmPrivateKey.java
index 83810e3b..8eac20d4 100644
--- a/src/net/named_data/jndn/security/tpm/TpmPrivateKey.java
+++ b/src/net/named_data/jndn/security/tpm/TpmPrivateKey.java
@@ -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;
@@ -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.
@@ -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
@@ -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.
@@ -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.
*/
@@ -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();
diff --git a/tests/src/net/named_data/jndn/tests/integration_tests/TestKeyChain.java b/tests/src/net/named_data/jndn/tests/integration_tests/TestKeyChain.java
index 2e7fc404..95c26ddf 100644
--- a/tests/src/net/named_data/jndn/tests/integration_tests/TestKeyChain.java
+++ b/tests/src/net/named_data/jndn/tests/integration_tests/TestKeyChain.java
@@ -32,7 +32,9 @@
import net.named_data.jndn.security.tpm.Tpm;
import net.named_data.jndn.security.tpm.TpmBackEnd;
import net.named_data.jndn.security.v2.CertificateV2;
+import net.named_data.jndn.security.SafeBag;
import net.named_data.jndn.util.Common;
+import net.named_data.jndn.util.Blob;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
@@ -216,7 +218,46 @@ public class TestKeyChain {
assertTrue(!fixture_.keyChain_.getPib().getIdentities_().getIdentities_().containsKey
(identityName));
- }
+
+ // Test import key
+ Blob testKey = new Blob(new byte[]
+ {-128, -3, 2, 23, 6, -3, 1, 43, 7, 43, 8, 3, 110, 100, 110, 8, 4, 116, 101, 115, 116, 8, 3, 75, 69, 89, 8,
+ 8, -109, 32, -119, 15, 65, 56, 25, 127, 8, 4, 115, 101, 108, 102, 8, 9, -3, 0, 0, 1, 110, -40, -122, -80,
+ 60, 20, 9, 24, 1, 2, 25, 4, 0, 54, -18, -128, 21, 91, 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6,
+ 8, 42, -122, 72, -50, 61, 3, 1, 7, 3, 66, 0, 4, 44, 23, -66, 73, -9, 119, -44, 66, -10, -82, -91, 73, -96,
+ -15, 104, -6, 53, 119, 41, -34, -73, -71, 76, 40, 34, -67, -66, -37, 113, 32, -110, 87, 10, 46, -81, 101,
+ -54, 38, 98, 81, -46, 110, 4, -69, 78, -123, -109, -15, -103, -120, -64, 124, 49, 72, -47, 77, -122, -62,
+ 64, 82, 17, 2, -26, -39, 22, 75, 27, 1, 3, 28, 28, 7, 26, 8, 3, 110, 100, 110, 8, 4, 116, 101, 115, 116, 8,
+ 3, 75, 69, 89, 8, 8, -109, 32, -119, 15, 65, 56, 25, 127, -3, 0, -3, 38, -3, 0, -2, 15, 49, 57, 55, 48, 48,
+ 49, 48, 49, 84, 48, 48, 48, 48, 48, 48, -3, 0, -1, 15, 50, 48, 51, 57, 49, 50, 48, 49, 84, 48, 48, 48, 53,
+ 51, 53, 23, 71, 48, 69, 2, 33, 0, -61, -49, -65, 125, 21, 121, -34, -98, 60, -25, -5, 53, -32, -120, -65,
+ 26, 8, -37, -63, -125, 117, -48, -86, 121, -65, -100, 61, 21, -94, -118, 120, 40, 2, 32, 73, 114, -77, 120,
+ 113, -5, -52, -126, -26, -88, -81, 115, -11, 15, 78, 21, -85, -113, -38, -114, 127, -107, 13, -81, 13, 23,
+ -67, -5, 118, 119, 19, -112, -127, -26, 48, -127, -29, 48, 78, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 13,
+ 48, 65, 48, 41, 6, 9, 42, -122, 72, -122, -9, 13, 1, 5, 12, 48, 28, 4, 8, 62, -1, 17, 54, -107, 101, 80,
+ 109, 2, 2, 8, 0, 48, 12, 6, 8, 42, -122, 72, -122, -9, 13, 2, 9, 5, 0, 48, 20, 6, 8, 42, -122, 72, -122, -9,
+ 13, 3, 7, 4, 8, 17, -36, -101, 19, 19, 38, 9, 7, 4, -127, -112, -45, -43, -18, -67, -55, 85, 91, 124, 27,
+ -123, -48, 127, 107, -49, -98, 51, 36, -123, 124, -78, -17, -118, 100, 126, -61, -64, 8, -73, 69, 40, 39,
+ -96, -14, -18, -23, -37, -16, -88, -80, 90, 6, -48, 108, 109, 101, 49, 122, 74, -120, -112, -27, -18, -6,
+ -111, -101, 117, -116, -100, 83, -45, 7, 19, 79, -87, 107, -47, 13, -51, -113, 40, -117, -17, 113, -59, 100,
+ 107, -66, -40, -71, 55, 39, 79, 97, -100, 82, -94, -110, -104, -91, -110, 21, 1, -1, 102, 95, -22, -111,
+ 112, -25, -59, 97, 60, -80, 107, -6, -70, 18, -17, -83, -53, -122, 42, -58, 82, 96, -30, -76, -18, -34, -5,
+ -71, -70, 66, 114, 34, -7, 24, -31, -2, -49, -23, 20, 75, 94, -98, 25, -69, 46, 85, -76, 127, 125, -88, 117}
+ );
+ Blob password = new Blob(new byte[]
+ {112, 97, 115, 115, 119, 111, 114, 100}
+ );
+ Name testName = new Name("/ndn/test/");
+
+ try {
+ SafeBag safebag = new SafeBag(testKey);
+ fixture_.keyChain_.importSafeBag(safebag, password.buf());
+ } catch (Throwable ex) {
+ fail("Unexpected exception: " + ex.getMessage());
+ }
+ assertTrue(fixture_.keyChain_.getPib().getIdentities_().getIdentities_().containsKey
+ (testName));
+ }
@Test
public void
diff --git a/tests/src/net/named_data/jndn/tests/unit_tests/TestTpmPrivateKey.java b/tests/src/net/named_data/jndn/tests/unit_tests/TestTpmPrivateKey.java
index 8bc97e89..f42d01f5 100644
--- a/tests/src/net/named_data/jndn/tests/unit_tests/TestTpmPrivateKey.java
+++ b/tests/src/net/named_data/jndn/tests/unit_tests/TestTpmPrivateKey.java
@@ -196,7 +196,7 @@ public EcKeyTestData()
// debug KeyTestData[] keyTestData = new KeyTestData[2];
KeyTestData[] keyTestData = new KeyTestData[1];
-
+
@Before
public void
setUp() throws EncodingException, CertificateV2.Error
@@ -263,12 +263,12 @@ public EcKeyTestData()
// Save the key in encrypted PKCS #8 format and resave as unencrypted.
Blob savedEncryptedPkcs8Key = null;
try {
- savedEncryptedPkcs8Key = encryptedKey8.toEncryptedPkcs8(password);
+ savedEncryptedPkcs8Key = encryptedKey8.toEncryptedPkcs8(new Blob("password").buf());
} catch (Throwable ex) {
fail("Unexpected exception: " + ex.getMessage());
}
key8 = new TpmPrivateKey();
- key8.loadEncryptedPkcs8(savedEncryptedPkcs8Key.buf(), password);
+ key8.loadEncryptedPkcs8(savedEncryptedPkcs8Key.buf(), new Blob("password").buf());
Blob resavedPkcs8Key = key8.toPkcs8();
assertTrue(resavedPkcs8Key.equals(new Blob(pkcs8)));
}
@@ -325,7 +325,7 @@ public EcKeyTestData()
@Test
public void
- testGenerateKey()
+ testGenerateKey()
throws TpmPrivateKey.Error, UnrecognizedKeyFormatException,
NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException,
SignatureException