diff --git a/base/src/main/java/org/mozilla/jss/pkcs7/EncryptedContentInfo.java b/base/src/main/java/org/mozilla/jss/pkcs7/EncryptedContentInfo.java
index 48a3ff482..6cf30b2c8 100644
--- a/base/src/main/java/org/mozilla/jss/pkcs7/EncryptedContentInfo.java
+++ b/base/src/main/java/org/mozilla/jss/pkcs7/EncryptedContentInfo.java
@@ -40,6 +40,8 @@
import org.mozilla.jss.crypto.TokenException;
import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
import org.mozilla.jss.pkix.primitive.PBEParameter;
+import org.mozilla.jss.pkix.primitive.PBES2Params;
+import org.mozilla.jss.pkix.primitive.PBKDF2Params;
import org.mozilla.jss.util.Password;
/**
@@ -236,27 +238,49 @@ public static EncryptedContentInfo createCRSCompatibleEncryptedContentInfo(OBJEC
}
// get the key gen parameters
- AlgorithmIdentifier algid = contentEncryptionAlgorithm;
- KeyGenAlgorithm kgAlg = KeyGenAlgorithm.fromOID( algid.getOID() );
+ KeyGenAlgorithm kgAlg = KeyGenAlgorithm.fromOID( contentEncryptionAlgorithm.getOID() );
if( !(kgAlg instanceof PBEAlgorithm) ) {
throw new NoSuchAlgorithmException("KeyGenAlgorithm is not a"+
" PBE algorithm");
}
- ASN1Value params = algid.getParameters();
+ ASN1Value params = contentEncryptionAlgorithm.getParameters();
if( params == null ) {
throw new InvalidAlgorithmParameterException(
"PBE algorithms require parameters");
}
- PBEParameter pbeParams;
- if( params instanceof PBEParameter) {
- pbeParams = (PBEParameter) params;
- } else {
+ byte[] salt = null;
+ int iterations = 0;
+ if(!kgAlg.toOID().equals(PBEAlgorithm.PBE_PKCS5_PBES2.toOID())) {
+ PBEParameter pbeParams;
+ if( params instanceof PBEParameter) {
+ pbeParams = (PBEParameter) params;
+ } else {
+ byte[] encodedParams = ASN1Util.encode(params);
+ pbeParams = (PBEParameter)
+ ASN1Util.decode( PBEParameter.getTemplate(), encodedParams );
+ }
+ salt = pbeParams.getSalt();
+ iterations = pbeParams.getIterations();
+ }
+ else {
byte[] encodedParams = ASN1Util.encode(params);
- pbeParams = (PBEParameter)
- ASN1Util.decode( PBEParameter.getTemplate(), encodedParams );
+ PBES2Params pbe2Params = (PBES2Params)
+ ASN1Util.decode( PBES2Params.getTemplate(), encodedParams);
+ AlgorithmIdentifier keyDerivationFunc = pbe2Params.getKeyDerivationFunc();
+ if(!keyDerivationFunc.getOID().equals(PBEAlgorithm.PBE_PKCS5_PBKDF2.toOID())) {
+ throw new InvalidAlgorithmParameterException("PBEs2 requires a PBKDF2 keyDerivationFunc"
+ + keyDerivationFunc.getOID().toDottedString());
+ }
+ byte[] encodedPBKParams = ASN1Util.encode(keyDerivationFunc.getParameters());
+ PBKDF2Params pbkParams = (PBKDF2Params) ASN1Util.decode(
+ PBKDF2Params.getTemplate(), encodedPBKParams);
+ salt = pbkParams.getSalt();
+ iterations = pbkParams.getIterations();
}
+
+
PBEKeyGenParams kgp = new PBEKeyGenParams(pass,
- pbeParams.getSalt(), pbeParams.getIterations() );
+ salt, iterations );
try {
// compute the key and IV
diff --git a/base/src/main/java/org/mozilla/jss/pkix/primitive/PBES2Params.java b/base/src/main/java/org/mozilla/jss/pkix/primitive/PBES2Params.java
new file mode 100644
index 000000000..c5393b084
--- /dev/null
+++ b/base/src/main/java/org/mozilla/jss/pkix/primitive/PBES2Params.java
@@ -0,0 +1,114 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.jss.pkix.primitive;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+
+/**
+ * PKCS #5 PBES2Parameter
+ */
+public class PBES2Params implements ASN1Value {
+
+ ///////////////////////////////////////////////////////////////////////
+ // members and member access
+ ///////////////////////////////////////////////////////////////////////
+ private AlgorithmIdentifier keyDerivationFunc;
+ private AlgorithmIdentifier encryptionScheme;
+ private SEQUENCE sequence;
+
+ public AlgorithmIdentifier getKeyDerivationFunc() {
+ return keyDerivationFunc;
+ }
+
+ public AlgorithmIdentifier getEncryptionScheme() {
+ return encryptionScheme;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////
+ // constructors
+ ///////////////////////////////////////////////////////////////////////
+
+
+ public PBES2Params(AlgorithmIdentifier keyDerivationFunc, AlgorithmIdentifier encryptionScheme) {
+ this.keyDerivationFunc = keyDerivationFunc;
+ this.encryptionScheme = encryptionScheme;
+ sequence = new SEQUENCE();
+ sequence.addElement( keyDerivationFunc );
+ sequence.addElement( encryptionScheme );
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // DER encoding
+ ///////////////////////////////////////////////////////////////////////
+
+ private static final Tag TAG = SEQUENCE.TAG;
+ @Override
+ public Tag getTag() {
+ return TAG;
+ }
+
+ @Override
+ public void encode(OutputStream ostream) throws IOException {
+ sequence.encode(ostream);
+ }
+
+ @Override
+ public void encode(Tag implicitTag, OutputStream ostream)
+ throws IOException
+ {
+ sequence.encode(implicitTag, ostream);
+ }
+
+
+ private static final Template templateInstance = new Template();
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A template class for decoding a PBES2Params.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+ seqt.addElement( AlgorithmIdentifier.getTemplate() );
+ seqt.addElement( AlgorithmIdentifier.getTemplate() );
+ }
+
+ @Override
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ @Override
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException
+ {
+ return decode(TAG, istream);
+ }
+
+ @Override
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException
+ {
+ SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag, istream);
+
+ return new PBES2Params( (AlgorithmIdentifier) seq.elementAt(0),
+ (AlgorithmIdentifier) seq.elementAt(1) );
+ }
+ }
+}
diff --git a/base/src/main/java/org/mozilla/jss/pkix/primitive/PBKDF2Params.java b/base/src/main/java/org/mozilla/jss/pkix/primitive/PBKDF2Params.java
new file mode 100644
index 000000000..877e49d32
--- /dev/null
+++ b/base/src/main/java/org/mozilla/jss/pkix/primitive/PBKDF2Params.java
@@ -0,0 +1,174 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.jss.pkix.primitive;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.mozilla.jss.asn1.ASN1Template;
+import org.mozilla.jss.asn1.ASN1Value;
+import org.mozilla.jss.asn1.CHOICE;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.Tag;
+
+/**
+ * PKCS #5 PBKDF2-Params.
+ */
+public class PBKDF2Params implements ASN1Value {
+
+ ///////////////////////////////////////////////////////////////////////
+ // members and member access
+ ///////////////////////////////////////////////////////////////////////
+ private byte[] salt;
+ private AlgorithmIdentifier otherSource;
+ private int iterations;
+ private int keyLength;
+ private AlgorithmIdentifier prf;
+ private SEQUENCE sequence;
+
+ public byte[] getSalt() {
+ return salt;
+ }
+
+ public int getIterations() {
+ return iterations;
+ }
+
+ public AlgorithmIdentifier getOtherSource() {
+ return otherSource;
+ }
+
+ public int getKeyLength() {
+ return keyLength;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////
+ // constructors
+ ///////////////////////////////////////////////////////////////////////
+
+ /**
+ * Creates a PBKDF2Params from a salt and iteration count
+ */
+ public PBKDF2Params(byte[] salt, AlgorithmIdentifier otherSource,
+ int iterations, int keyLength, AlgorithmIdentifier prf) {
+ this.salt = salt;
+ this.otherSource = otherSource;
+ this.iterations = iterations;
+ this.keyLength = keyLength;
+ this.prf = prf;
+ sequence = new SEQUENCE();
+ if(salt!=null) {
+ sequence.addElement( new OCTET_STRING(salt) );
+ }
+ else {
+ sequence.addElement(otherSource);
+ }
+ sequence.addElement( new INTEGER(iterations) );
+ if(keyLength>0) {
+ sequence.addElement(new INTEGER(keyLength));
+ }
+ sequence.addElement(prf);
+ }
+
+ /**
+ * Creates a PBKDF2Params from a salt and iteration count
+ */
+ public PBKDF2Params(OCTET_STRING salt, AlgorithmIdentifier otherSource,
+ INTEGER iterations, INTEGER keyLength, AlgorithmIdentifier prf) {
+ this( salt.toByteArray(), otherSource, iterations.intValue(),
+ keyLength.intValue(), prf);
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // DER encoding
+ ///////////////////////////////////////////////////////////////////////
+
+ private static final Tag TAG = SEQUENCE.TAG;
+ @Override
+ public Tag getTag() {
+ return TAG;
+ }
+
+ @Override
+ public void encode(OutputStream ostream) throws IOException {
+ sequence.encode(ostream);
+ }
+
+ @Override
+ public void encode(Tag implicitTag, OutputStream ostream)
+ throws IOException
+ {
+ sequence.encode(implicitTag, ostream);
+ }
+
+
+ private static final Template templateInstance = new Template();
+ public static Template getTemplate() {
+ return templateInstance;
+ }
+
+ /**
+ * A template class for decoding a PBKDF2Params.
+ */
+ public static class Template implements ASN1Template {
+
+ private SEQUENCE.Template seqt;
+
+ public Template() {
+ seqt = new SEQUENCE.Template();
+
+ CHOICE.Template salt = CHOICE.getTemplate();
+ salt.addElement(OCTET_STRING.getTemplate());
+ salt.addElement(AlgorithmIdentifier.getTemplate());
+
+ seqt.addElement(salt);
+ seqt.addElement(INTEGER.getTemplate());
+ seqt.addOptionalElement(INTEGER.getTemplate());
+ seqt.addElement(AlgorithmIdentifier.getTemplate());
+ }
+
+ @Override
+ public boolean tagMatch(Tag tag) {
+ return TAG.equals(tag);
+ }
+
+ @Override
+ public ASN1Value decode(InputStream istream)
+ throws InvalidBERException, IOException
+ {
+ return decode(TAG, istream);
+ }
+
+ @Override
+ public ASN1Value decode(Tag implicitTag, InputStream istream)
+ throws InvalidBERException, IOException
+ {
+ OCTET_STRING specified = null;
+ AlgorithmIdentifier otherSource = null;
+
+ SEQUENCE seq = (SEQUENCE) seqt.decode(implicitTag, istream);
+
+ CHOICE salt = (CHOICE) seq.elementAt(0);
+ if (salt.getValue() instanceof OCTET_STRING saltValue) {
+ specified = saltValue;
+ }
+
+ if (salt.getValue() instanceof AlgorithmIdentifier saltSource) {
+ otherSource = saltSource;
+ }
+
+ return new PBKDF2Params( specified,
+ otherSource,
+ (INTEGER) seq.elementAt(1),
+ (INTEGER) seq.elementAt(2),
+ (AlgorithmIdentifier) seq.elementAt(3));
+ }
+ }
+}