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)); + } + } +}