diff options
author | MW <megan@cryptoworkshop.com> | 2019-01-17 16:16:20 +1100 |
---|---|---|
committer | MW <megan@cryptoworkshop.com> | 2019-01-17 16:16:20 +1100 |
commit | 3d578b981aad94eaee07fa444dd11f9323026e94 (patch) | |
tree | d64141ae1163cafb69a4e3fc26ab90b538d98ef6 /crypto | |
parent | Missing from previous commit (diff) | |
download | BouncyCastle.NET-ed25519-3d578b981aad94eaee07fa444dd11f9323026e94.tar.xz |
CMS ArchiveControl
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/src/asn1/misc/MiscObjectIdentifiers.cs | 2 | ||||
-rw-r--r-- | crypto/src/cmp/RevocationDetails.cs | 39 | ||||
-rw-r--r-- | crypto/src/cmp/RevocationDetailsBuilder.cs | 58 | ||||
-rw-r--r-- | crypto/src/cms/CMSEnvelopedDataGenerator.cs | 71 | ||||
-rw-r--r-- | crypto/src/cms/CMSEnvelopedGenerator.cs | 10 | ||||
-rw-r--r-- | crypto/src/cms/CMSProcessableByteArray.cs | 17 | ||||
-rw-r--r-- | crypto/src/cms/EnvelopedDataHelper.cs | 123 | ||||
-rw-r--r-- | crypto/src/cms/RecipientInfoGenerator.cs | 2 | ||||
-rw-r--r-- | crypto/src/crmf/CertificateRequestMessage.cs | 4 | ||||
-rw-r--r-- | crypto/src/crmf/CertificateRequestMessageBuilder.cs | 9 | ||||
-rw-r--r-- | crypto/src/crmf/PKIArchiveControlBuilder.cs | 61 | ||||
-rw-r--r-- | crypto/src/crypto/operators/Asn1Signature.cs | 4 | ||||
-rw-r--r-- | crypto/src/crypto/operators/CipherFactory.cs | 146 | ||||
-rw-r--r-- | crypto/src/crypto/operators/CmsContentEncryptorBuilder.cs | 155 | ||||
-rw-r--r-- | crypto/src/crypto/util/AlgorithmIdentifierFactory.cs | 105 | ||||
-rw-r--r-- | crypto/src/crypto/util/CipherKeyGeneratorFactory.cs | 101 | ||||
-rw-r--r-- | crypto/test/src/crmf/test/CrmfTest.cs | 191 |
17 files changed, 1091 insertions, 7 deletions
diff --git a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs index d344393dd..1ff19e737 100644 --- a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs +++ b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs @@ -50,6 +50,8 @@ namespace Org.BouncyCastle.Asn1.Misc public static readonly string Entrust = "1.2.840.113533.7"; public static readonly DerObjectIdentifier EntrustVersionExtension = new DerObjectIdentifier(Entrust + ".65.0"); + public static readonly DerObjectIdentifier cast5CBC = new DerObjectIdentifier(Entrust+ ".66.10"); + // // Ascom // diff --git a/crypto/src/cmp/RevocationDetails.cs b/crypto/src/cmp/RevocationDetails.cs new file mode 100644 index 000000000..6e1cb34c3 --- /dev/null +++ b/crypto/src/cmp/RevocationDetails.cs @@ -0,0 +1,39 @@ +using Org.BouncyCastle.Asn1.Cmp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Cmp +{ + public class RevocationDetails + { + private RevDetails revDetails; + + public RevocationDetails(RevDetails revDetails) + { + this.revDetails = revDetails; + } + + public X509Name Subject + { + get { return revDetails.CertDetails.Subject; } + } + + public X509Name Issuer + { + get { return revDetails.CertDetails.Issuer; } + } + + public BigInteger SerialNumber + { + get + { + return revDetails.CertDetails.SerialNumber.Value; // getCertDetails().getSerialNumber().getValue(); + } + } + + public RevDetails ToASN1Structure() + { + return revDetails; + } + } +} \ No newline at end of file diff --git a/crypto/src/cmp/RevocationDetailsBuilder.cs b/crypto/src/cmp/RevocationDetailsBuilder.cs new file mode 100644 index 000000000..464c0bb13 --- /dev/null +++ b/crypto/src/cmp/RevocationDetailsBuilder.cs @@ -0,0 +1,58 @@ +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cmp; +using Org.BouncyCastle.Asn1.Crmf; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Cmp +{ + public class RevocationDetailsBuilder + { + private readonly CertTemplateBuilder _templateBuilder = new CertTemplateBuilder(); + + public RevocationDetailsBuilder SetPublicKey(SubjectPublicKeyInfo publicKey) + { + if (publicKey != null) + { + _templateBuilder.SetPublicKey(publicKey); + } + + return this; + } + + public RevocationDetailsBuilder SetIssuer(X509Name issuer) + { + if (issuer != null) + { + _templateBuilder.SetIssuer(issuer); + } + + return this; + } + + public RevocationDetailsBuilder SetSerialNumber(BigInteger serialNumber) + { + if (serialNumber != null) + { + _templateBuilder.SetSerialNumber(new DerInteger(serialNumber)); + } + + return this; + } + + public RevocationDetailsBuilder SetSubject(X509Name subject) + { + if (subject != null) + { + _templateBuilder.SetSubject(subject); + } + + return this; + } + + public RevocationDetails build() + { + return new RevocationDetails(new RevDetails(_templateBuilder.Build())); + } + } +} \ No newline at end of file diff --git a/crypto/src/cms/CMSEnvelopedDataGenerator.cs b/crypto/src/cms/CMSEnvelopedDataGenerator.cs index d260e998a..8ba41161e 100644 --- a/crypto/src/cms/CMSEnvelopedDataGenerator.cs +++ b/crypto/src/cms/CMSEnvelopedDataGenerator.cs @@ -144,7 +144,7 @@ namespace Org.BouncyCastle.Cms try { CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid); - + keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength)); return Generate(content, encryptionOid, keyGen); @@ -155,6 +155,75 @@ namespace Org.BouncyCastle.Cms } } + + public CmsEnvelopedData Generate(CmsProcessable content, ICipherBuilderWithKey cipherBuilder) + { + AlgorithmIdentifier encAlgId = null; + KeyParameter encKey; + Asn1OctetString encContent; + + try + { + encKey = (KeyParameter) cipherBuilder.Key; + + MemoryStream collector = new MemoryStream(); + Stream bOut = cipherBuilder.BuildCipher(collector).Stream; + content.Write(bOut); + Platform.Dispose(bOut); + encContent = new BerOctetString(collector.ToArray()); + } + catch (SecurityUtilityException e) + { + throw new CmsException("couldn't create cipher.", e); + } + catch (InvalidKeyException e) + { + throw new CmsException("key invalid in message.", e); + } + catch (IOException e) + { + throw new CmsException("exception decoding algorithm parameters.", e); + } + + + Asn1EncodableVector recipientInfos = new Asn1EncodableVector(); + + foreach (RecipientInfoGenerator rig in recipientInfoGenerators) + { + try + { + recipientInfos.Add(rig.Generate(encKey, rand)); + } + catch (InvalidKeyException e) + { + throw new CmsException("key inappropriate for algorithm.", e); + } + catch (GeneralSecurityException e) + { + throw new CmsException("error making encrypted content.", e); + } + } + + EncryptedContentInfo eci = new EncryptedContentInfo( + CmsObjectIdentifiers.Data, + (AlgorithmIdentifier) cipherBuilder.AlgorithmDetails, + encContent); + + Asn1Set unprotectedAttrSet = null; + if (unprotectedAttributeGenerator != null) + { + Asn1.Cms.AttributeTable attrTable = unprotectedAttributeGenerator.GetAttributes(Platform.CreateHashtable()); + + unprotectedAttrSet = new BerSet(attrTable.ToAsn1EncodableVector()); + } + + ContentInfo contentInfo = new ContentInfo( + CmsObjectIdentifiers.EnvelopedData, + new EnvelopedData(null, new DerSet(recipientInfos), eci, unprotectedAttrSet)); + + return new CmsEnvelopedData(contentInfo); + } + /// <summary>Generate an enveloped object that contains an CMS Enveloped Data object.</summary> public CmsEnvelopedData Generate( CmsProcessable content, diff --git a/crypto/src/cms/CMSEnvelopedGenerator.cs b/crypto/src/cms/CMSEnvelopedGenerator.cs index f92ae3824..ed7e1edee 100644 --- a/crypto/src/cms/CMSEnvelopedGenerator.cs +++ b/crypto/src/cms/CMSEnvelopedGenerator.cs @@ -263,6 +263,16 @@ namespace Org.BouncyCastle.Cms recipientInfoGenerators.Add(karig); } + /// <summary> + /// Add a generator to produce the recipient info required. + /// </summary> + /// <param name="recipientInfoGenerator">a generator of a recipient info object.</param> + public void AddRecipientInfoGenerator(RecipientInfoGenerator recipientInfoGenerator) + { + recipientInfoGenerators.Add(recipientInfoGenerator); + } + + protected internal virtual AlgorithmIdentifier GetAlgorithmIdentifier( string encryptionOid, KeyParameter encKey, diff --git a/crypto/src/cms/CMSProcessableByteArray.cs b/crypto/src/cms/CMSProcessableByteArray.cs index a6ab9b6a2..b09935dd8 100644 --- a/crypto/src/cms/CMSProcessableByteArray.cs +++ b/crypto/src/cms/CMSProcessableByteArray.cs @@ -1,5 +1,7 @@ using System; using System.IO; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; namespace Org.BouncyCastle.Cms { @@ -9,13 +11,26 @@ namespace Org.BouncyCastle.Cms public class CmsProcessableByteArray : CmsProcessable, CmsReadable { + private readonly DerObjectIdentifier type; private readonly byte[] bytes; public CmsProcessableByteArray(byte[] bytes) - { + { + type = CmsObjectIdentifiers.Data; this.bytes = bytes; } + public CmsProcessableByteArray(DerObjectIdentifier type, byte[] bytes) + { + this.bytes = bytes; + this.type = type; + } + + public DerObjectIdentifier Type + { + get { return type; } + } + public virtual Stream GetInputStream() { return new MemoryStream(bytes, false); diff --git a/crypto/src/cms/EnvelopedDataHelper.cs b/crypto/src/cms/EnvelopedDataHelper.cs new file mode 100644 index 000000000..89ec79691 --- /dev/null +++ b/crypto/src/cms/EnvelopedDataHelper.cs @@ -0,0 +1,123 @@ +using System.Collections; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Operators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Utilities; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Cms +{ + public class EnvelopedDataHelper + { + private static readonly IDictionary BaseCipherNames = Platform.CreateHashtable(); + private static readonly IDictionary MacAlgNames = Platform.CreateHashtable(); + + private static readonly IDictionary prfs = Platform.CreateHashtable(); + + + public delegate IDigest DigestCreator(); + + static EnvelopedDataHelper() + { + prfs.Add(PkcsObjectIdentifiers.IdHmacWithSha1, new DigestProvider(delegate () { return new Sha1Digest(); })); + prfs.Add(PkcsObjectIdentifiers.IdHmacWithSha224, new DigestProvider(delegate () { return new Sha224Digest(); })); + prfs.Add(PkcsObjectIdentifiers.IdHmacWithSha256, new DigestProvider(delegate () { return new Sha256Digest(); })); + prfs.Add(PkcsObjectIdentifiers.IdHmacWithSha384, new DigestProvider(delegate () { return new Sha384Digest(); })); + prfs.Add(PkcsObjectIdentifiers.IdHmacWithSha512, new DigestProvider(delegate () { return new Sha512Digest(); })); + + + BaseCipherNames.Add(PkcsObjectIdentifiers.DesEde3Cbc, "DESEDE"); + BaseCipherNames.Add(NistObjectIdentifiers.IdAes128Cbc, "AES"); + BaseCipherNames.Add(NistObjectIdentifiers.IdAes192Cbc, "AES"); + BaseCipherNames.Add(NistObjectIdentifiers.IdAes256Cbc, "AES"); + + MacAlgNames.Add(PkcsObjectIdentifiers.DesEde3Cbc, "DESEDEMac"); + MacAlgNames.Add(NistObjectIdentifiers.IdAes128Cbc, "AESMac"); + MacAlgNames.Add(NistObjectIdentifiers.IdAes192Cbc, "AESMac"); + MacAlgNames.Add(NistObjectIdentifiers.IdAes256Cbc, "AESMac"); + MacAlgNames.Add(PkcsObjectIdentifiers.RC2Cbc, "RC2Mac"); + } + + static IDigest GetPrf(AlgorithmIdentifier algID) + { + return ((DigestCreator)prfs[algID]).Invoke(); + } + + + static IWrapper CreateRFC3211Wrapper(DerObjectIdentifier algorithm) + + { + if (NistObjectIdentifiers.IdAes128Cbc.Equals(algorithm) + || NistObjectIdentifiers.IdAes192Cbc.Equals(algorithm) + || NistObjectIdentifiers.IdAes256Cbc.Equals(algorithm)) + { + return new Rfc3211WrapEngine(new AesEngine()); + } + else if (PkcsObjectIdentifiers.DesEde3Cbc.Equals(algorithm)) + { + return new Rfc3211WrapEngine(new DesEdeEngine()); + } + else if (OiwObjectIdentifiers.DesCbc.Equals(algorithm)) + { + return new Rfc3211WrapEngine(new DesEngine()); + } + else if (PkcsObjectIdentifiers.RC2Cbc.Equals(algorithm)) + { + return new Rfc3211WrapEngine(new RC2Engine()); + } + else + { + throw new CmsException("cannot recognise wrapper: " + algorithm); + } + } + + + + public static object CreateContentCipher(bool forEncryption, ICipherParameters encKey, + AlgorithmIdentifier encryptionAlgID) + + { + return CipherFactory.CreateContentCipher(forEncryption, encKey, encryptionAlgID); + } + + + public AlgorithmIdentifier GenerateEncryptionAlgID(DerObjectIdentifier encryptionOID, KeyParameter encKey, SecureRandom random) + + { + return AlgorithmIdentifierFactory.GenerateEncryptionAlgID(encryptionOID, encKey.GetKey().Length * 8, random); + } + + public CipherKeyGenerator CreateKeyGenerator(DerObjectIdentifier algorithm, SecureRandom random) + + { + return CipherKeyGeneratorFactory.CreateKeyGenerator(algorithm, random); + } + + + } + + // This exists because we can't directly put a delegate in a map as it is + // not an object. + internal class DigestProvider + { + private readonly EnvelopedDataHelper.DigestCreator creator; + + public DigestProvider(EnvelopedDataHelper.DigestCreator creator) + { + this.creator = creator; + } + + public IDigest Create() + { + return creator.Invoke(); + } + } +} \ No newline at end of file diff --git a/crypto/src/cms/RecipientInfoGenerator.cs b/crypto/src/cms/RecipientInfoGenerator.cs index c41db6122..75f5dcc33 100644 --- a/crypto/src/cms/RecipientInfoGenerator.cs +++ b/crypto/src/cms/RecipientInfoGenerator.cs @@ -6,7 +6,7 @@ using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Cms { - interface RecipientInfoGenerator + public interface RecipientInfoGenerator { /// <summary> /// Generate a RecipientInfo object for the given key. diff --git a/crypto/src/crmf/CertificateRequestMessage.cs b/crypto/src/crmf/CertificateRequestMessage.cs index 087e8a933..5b5d37c9e 100644 --- a/crypto/src/crmf/CertificateRequestMessage.cs +++ b/crypto/src/crmf/CertificateRequestMessage.cs @@ -211,8 +211,8 @@ namespace Org.BouncyCastle.Crmf calculator.Stream.Write(b,0,b.Length); } else - { - byte[] b = certReqMsg.GetDerEncoded(); + { + byte[] b = certReqMsg.CertReq.GetDerEncoded(); calculator.Stream.Write(b,0,b.Length); } diff --git a/crypto/src/crmf/CertificateRequestMessageBuilder.cs b/crypto/src/crmf/CertificateRequestMessageBuilder.cs index 384f6a965..9c3cf954d 100644 --- a/crypto/src/crmf/CertificateRequestMessageBuilder.cs +++ b/crypto/src/crmf/CertificateRequestMessageBuilder.cs @@ -95,6 +95,12 @@ namespace Org.BouncyCastle.Crmf return this; } + public CertificateRequestMessageBuilder AddControl(IControl control) + { + _controls.Add(control); + return this; + } + public CertificateRequestMessageBuilder SetProofOfPossessionSignKeySigner(ISignatureFactory popoSignatureFactory) { if (_popoPrivKey != null || _popRaVerified != null || _agreeMac != null) @@ -102,7 +108,8 @@ namespace Org.BouncyCastle.Crmf throw new InvalidOperationException("only one proof of possession is allowed."); } - this._popoType = ProofOfPossession.TYPE_KEY_ENCIPHERMENT; + this._popSigner = popoSignatureFactory; + return this; } diff --git a/crypto/src/crmf/PKIArchiveControlBuilder.cs b/crypto/src/crmf/PKIArchiveControlBuilder.cs new file mode 100644 index 000000000..f43ecd4ec --- /dev/null +++ b/crypto/src/crmf/PKIArchiveControlBuilder.cs @@ -0,0 +1,61 @@ +using System; +using System.IO; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Crmf; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Cms; +using Org.BouncyCastle.Crypto; + +namespace Org.BouncyCastle.Crmf +{ + public class PKIArchiveControlBuilder + { + private CmsEnvelopedDataGenerator envGen; + private CmsProcessableByteArray keyContent; + + /// <summary> + ///Basic constructor - specify the contents of the PKIArchiveControl structure. + /// </summary> + /// <param name="privateKeyInfo">the private key to be archived.</param> + /// <param name="generalName">the general name to be associated with the private key.</param> + /// + public PKIArchiveControlBuilder(PrivateKeyInfo privateKeyInfo, GeneralName generalName) + { + EncKeyWithID encKeyWithID = new EncKeyWithID(privateKeyInfo, generalName); + + try + { + this.keyContent = new CmsProcessableByteArray(CrmfObjectIdentifiers.id_ct_encKeyWithID, encKeyWithID.GetEncoded()); + } + catch (IOException e) + { + throw new InvalidOperationException("unable to encode key and general name info"); + } + + this.envGen = new CmsEnvelopedDataGenerator(); + } + + + + + ///<summary>Add a recipient generator to this control.</summary> + ///<param name="recipientGen"> recipient generator created for a specific recipient.</param> + ///<returns>this builder object.</returns> + public PKIArchiveControlBuilder AddRecipientGenerator(RecipientInfoGenerator recipientGen) + { + envGen.AddRecipientInfoGenerator(recipientGen); + return this; + } + + /// <summary>Build the PKIArchiveControl using the passed in encryptor to encrypt its contents.</summary> + /// <param name="contentEncryptor">a suitable content encryptor.</param> + /// <returns>a PKIArchiveControl object.</returns> + public PkiArchiveControl Build(ICipherBuilderWithKey contentEncryptor) + { + CmsEnvelopedData envContent = envGen.Generate(keyContent, contentEncryptor); + EnvelopedData envD = EnvelopedData.GetInstance(envContent.ContentInfo.Content); + return new PkiArchiveControl(new PkiArchiveOptions(new EncryptedKey(envD))); + } +} +} \ No newline at end of file diff --git a/crypto/src/crypto/operators/Asn1Signature.cs b/crypto/src/crypto/operators/Asn1Signature.cs index 3962a4a15..66050789e 100644 --- a/crypto/src/crypto/operators/Asn1Signature.cs +++ b/crypto/src/crypto/operators/Asn1Signature.cs @@ -12,6 +12,7 @@ using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Signers; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Collections; @@ -346,7 +347,8 @@ namespace Org.BouncyCastle.Crypto.Operators } public IStreamCalculator CreateCalculator() - { + { + ISigner verifier = SignerUtilities.InitSigner(X509Utilities.GetSignatureName(algID), false, publicKey, null); return new DefaultVerifierCalculator(verifier); diff --git a/crypto/src/crypto/operators/CipherFactory.cs b/crypto/src/crypto/operators/CipherFactory.cs new file mode 100644 index 000000000..11a9faef9 --- /dev/null +++ b/crypto/src/crypto/operators/CipherFactory.cs @@ -0,0 +1,146 @@ +using System; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Kisa; +using Org.BouncyCastle.Asn1.Misc; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Ntt; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Paddings; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Utilities; + +namespace Org.BouncyCastle.Crypto.Operators +{ + public class CipherFactory + { + private static readonly short[] rc2Ekb = + { + 0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5, + 0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5, + 0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef, + 0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d, + 0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb, + 0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d, + 0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3, + 0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61, + 0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1, + 0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21, + 0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42, + 0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f, + 0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7, + 0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15, + 0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7, + 0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd + }; + + public static object CreateContentCipher(bool forEncryption, ICipherParameters encKey, + AlgorithmIdentifier encryptionAlgID) + { + DerObjectIdentifier encAlg = encryptionAlgID.Algorithm; + + if (encAlg.Equals(PkcsObjectIdentifiers.Rc4)) + { + IStreamCipher cipher = new RC4Engine(); + + cipher.Init(forEncryption, encKey); + + return cipher; + } + else + { + BufferedBlockCipher cipher = CreateCipher(encryptionAlgID.Algorithm); + + Asn1Object sParams = encryptionAlgID.Parameters.ToAsn1Object(); + + if (sParams != null && !(sParams is DerNull)) + { + if (encAlg.Equals(PkcsObjectIdentifiers.DesEde3Cbc) + || encAlg.Equals(AlgorithmIdentifierFactory.IDEA_CBC) + || encAlg.Equals(NistObjectIdentifiers.IdAes128Cbc) + || encAlg.Equals(NistObjectIdentifiers.IdAes192Cbc) + || encAlg.Equals(NistObjectIdentifiers.IdAes256Cbc) + || encAlg.Equals(NttObjectIdentifiers.IdCamellia128Cbc) + || encAlg.Equals(NttObjectIdentifiers.IdCamellia192Cbc) + || encAlg.Equals(NttObjectIdentifiers.IdCamellia256Cbc) + || encAlg.Equals(KisaObjectIdentifiers.IdSeedCbc) + || encAlg.Equals(OiwObjectIdentifiers.DesCbc)) + { + cipher.Init(forEncryption, new ParametersWithIV(encKey, + Asn1OctetString.GetInstance(sParams).GetOctets())); + } + else if (encAlg.Equals(AlgorithmIdentifierFactory.CAST5_CBC)) + { + Cast5CbcParameters cbcParams = Cast5CbcParameters.GetInstance(sParams); + + cipher.Init(forEncryption, new ParametersWithIV(encKey, cbcParams.GetIV())); + } + else if (encAlg.Equals(PkcsObjectIdentifiers.RC2Cbc)) + { + RC2CbcParameter cbcParams = RC2CbcParameter.GetInstance(sParams); + + cipher.Init(forEncryption, new ParametersWithIV(new RC2Parameters(((KeyParameter)encKey).GetKey(), rc2Ekb[cbcParams.RC2ParameterVersion.IntValue]), cbcParams.GetIV())); + } + else + { + throw new InvalidOperationException("cannot match parameters"); + } + } + else + { + if (encAlg.Equals(PkcsObjectIdentifiers.DesEde3Cbc) + || encAlg.Equals(AlgorithmIdentifierFactory.IDEA_CBC) + || encAlg.Equals(AlgorithmIdentifierFactory.CAST5_CBC)) + { + cipher.Init(forEncryption, new ParametersWithIV(encKey, new byte[8])); + } + else + { + cipher.Init(forEncryption, encKey); + } + } + + return cipher; + } + + } + + private static BufferedBlockCipher CreateCipher(DerObjectIdentifier algorithm) + { + IBlockCipher cipher; + + if (NistObjectIdentifiers.IdAes128Cbc.Equals(algorithm) + || NistObjectIdentifiers.IdAes192Cbc.Equals(algorithm) + || NistObjectIdentifiers.IdAes256Cbc.Equals(algorithm)) + { + cipher = new CbcBlockCipher(new AesEngine()); + } + else if (PkcsObjectIdentifiers.DesEde3Cbc.Equals(algorithm)) + { + cipher = new CbcBlockCipher(new DesEdeEngine()); + } + else if (OiwObjectIdentifiers.DesCbc.Equals(algorithm)) + { + cipher = new CbcBlockCipher(new DesEngine()); + } + else if (PkcsObjectIdentifiers.RC2Cbc.Equals(algorithm)) + { + cipher = new CbcBlockCipher(new RC2Engine()); + } + else if (MiscObjectIdentifiers.cast5CBC.Equals(algorithm)) + { + cipher = new CbcBlockCipher(new Cast5Engine()); + } + else + { + throw new InvalidOperationException("cannot recognise cipher: " + algorithm); + } + + return new PaddedBufferedBlockCipher(cipher, new Pkcs7Padding()); + } + + } +} \ No newline at end of file diff --git a/crypto/src/crypto/operators/CmsContentEncryptorBuilder.cs b/crypto/src/crypto/operators/CmsContentEncryptorBuilder.cs new file mode 100644 index 000000000..f7ddf4db6 --- /dev/null +++ b/crypto/src/crypto/operators/CmsContentEncryptorBuilder.cs @@ -0,0 +1,155 @@ +using System.Collections; +using System.IO; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Ntt; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Cms; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Operators +{ + public class CmsContentEncryptorBuilder + { + private static readonly IDictionary keySizes = Platform.CreateHashtable(); + + static CmsContentEncryptorBuilder() + { + keySizes[NistObjectIdentifiers.IdAes128Cbc] = 128; + keySizes[NistObjectIdentifiers.IdAes192Cbc] =192; + keySizes[NistObjectIdentifiers.IdAes256Cbc] =256; + + + keySizes[NttObjectIdentifiers.IdCamellia128Cbc] =128; + keySizes[NttObjectIdentifiers.IdCamellia192Cbc] =192; + keySizes[NttObjectIdentifiers.IdCamellia256Cbc] =256; + } + + private static int getKeySize(DerObjectIdentifier oid) + { + if (keySizes.Contains(oid)) + { + return (int)keySizes[oid]; + } + + return -1; + } + + private readonly DerObjectIdentifier encryptionOID; + private readonly int keySize; + + + private EnvelopedDataHelper helper = new EnvelopedDataHelper(); + private SecureRandom random; + + public CmsContentEncryptorBuilder(DerObjectIdentifier encryptionOID):this(encryptionOID, getKeySize(encryptionOID)) { + } + + public CmsContentEncryptorBuilder(DerObjectIdentifier encryptionOID, int keySize) + { + this.encryptionOID = encryptionOID; + this.keySize = keySize; + } + + public ICipherBuilderWithKey Build() + { + return new DefaultCipherBuilderWithKey(encryptionOID,keySize,random,new EnvelopedDataHelper()); + } + + } + + public class DefaultCipherBuilderWithKey:ICipherBuilderWithKey + { + + private readonly KeyParameter encKey; + private AlgorithmIdentifier algorithmIdentifier; + + + + + public DefaultCipherBuilderWithKey(DerObjectIdentifier encryptionOID, int keySize, SecureRandom random,EnvelopedDataHelper helper) + { + if (random == null) + { + random= new SecureRandom(); + } + + CipherKeyGenerator keyGen = helper.CreateKeyGenerator(encryptionOID, random); + encKey = new KeyParameter(keyGen.GenerateKey()); + algorithmIdentifier = helper.GenerateEncryptionAlgID(encryptionOID, encKey, random); + // cipher = EnvelopedDataHelper.CreateContentCipher(true, encKey, algorithmIdentifier); + } + + + public object AlgorithmDetails + { + get { return algorithmIdentifier; } + } + public int GetMaxOutputSize(int inputLen) + { + throw new System.NotImplementedException(); + } + + public ICipher BuildCipher(Stream stream) + { + + object cipher = EnvelopedDataHelper.CreateContentCipher(true, encKey, algorithmIdentifier); + + // + // BufferedBlockCipher + // IStreamCipher + // + + if (cipher is IStreamCipher) + { + cipher = new BufferedStreamCipher((IStreamCipher)cipher); + } + + if (stream == null) + { + stream = new MemoryStream(); + } + + return new BufferedCipherWrapper((IBufferedCipher)cipher,stream); + } + + public ICipherParameters Key + { + get { return encKey; } + } + } + + public class BufferedCipherWrapper : ICipher + { + private readonly IBufferedCipher bufferedCipher; + private readonly CipherStream stream; + + public BufferedCipherWrapper(IBufferedCipher bufferedCipher, Stream source) + { + this.bufferedCipher = bufferedCipher; + stream = new CipherStream(source, bufferedCipher, bufferedCipher); + } + + public int GetMaxOutputSize(int inputLen) + { + return bufferedCipher.GetOutputSize(inputLen); + } + + public int GetUpdateOutputSize(int inputLen) + { + return bufferedCipher.GetUpdateOutputSize(inputLen); + } + + public Stream Stream + { + get { return stream; } + } + } + + + + +} \ No newline at end of file diff --git a/crypto/src/crypto/util/AlgorithmIdentifierFactory.cs b/crypto/src/crypto/util/AlgorithmIdentifierFactory.cs new file mode 100644 index 000000000..73458f0ea --- /dev/null +++ b/crypto/src/crypto/util/AlgorithmIdentifierFactory.cs @@ -0,0 +1,105 @@ +using System; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Kisa; +using Org.BouncyCastle.Asn1.Misc; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Ntt; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Utilities +{ + public class AlgorithmIdentifierFactory + { + public static readonly DerObjectIdentifier IDEA_CBC = new DerObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2"); + public static readonly DerObjectIdentifier CAST5_CBC = new DerObjectIdentifier("1.2.840.113533.7.66.10"); + + private static readonly short[] rc2Table = { + 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0, + 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a, + 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36, + 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c, + 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60, + 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa, + 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e, + 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf, + 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6, + 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3, + 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c, + 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2, + 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5, + 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5, + 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f, + 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab + }; + + + /** + * Create an AlgorithmIdentifier for the passed in encryption algorithm. + * + * @param encryptionOID OID for the encryption algorithm + * @param keySize key size in bits (-1 if unknown) + * @param random SecureRandom to use for parameter generation. + * @return a full AlgorithmIdentifier including parameters + * @throws IllegalArgumentException if encryptionOID cannot be matched + */ + public static AlgorithmIdentifier GenerateEncryptionAlgID(DerObjectIdentifier encryptionOID, int keySize, SecureRandom random) + + { + if (encryptionOID.Equals(NistObjectIdentifiers.IdAes128Cbc) + || encryptionOID.Equals(NistObjectIdentifiers.IdAes192Cbc) + || encryptionOID.Equals(NistObjectIdentifiers.IdAes256Cbc) + || encryptionOID.Equals(NttObjectIdentifiers.IdCamellia128Cbc) + || encryptionOID.Equals(NttObjectIdentifiers.IdCamellia192Cbc) + || encryptionOID.Equals(NttObjectIdentifiers.IdCamellia256Cbc) + || encryptionOID.Equals(KisaObjectIdentifiers.IdSeedCbc)) + { + byte[] iv = new byte[16]; + + random.NextBytes(iv); + + return new AlgorithmIdentifier(encryptionOID, new DerOctetString(iv)); + } + else if (encryptionOID.Equals(PkcsObjectIdentifiers.DesEde3Cbc) + || encryptionOID.Equals(IDEA_CBC) + || encryptionOID.Equals(OiwObjectIdentifiers.DesCbc)) + { + byte[] iv = new byte[8]; + + random.NextBytes(iv); + + return new AlgorithmIdentifier(encryptionOID, new DerOctetString(iv)); + } + else if (encryptionOID.Equals(CAST5_CBC)) + { + byte[] iv = new byte[8]; + + random.NextBytes(iv); + + Cast5CbcParameters cbcParams = new Cast5CbcParameters(iv, keySize); + + return new AlgorithmIdentifier(encryptionOID, cbcParams); + } + else if (encryptionOID.Equals(PkcsObjectIdentifiers.Rc4)) + { + return new AlgorithmIdentifier(encryptionOID, DerNull.Instance); + } + else if (encryptionOID.Equals(PkcsObjectIdentifiers.RC2Cbc)) + { + byte[] iv = new byte[8]; + + random.NextBytes(iv); + + RC2CbcParameter cbcParams = new RC2CbcParameter(rc2Table[128], iv); + + return new AlgorithmIdentifier(encryptionOID, cbcParams); + } + else + { + throw new InvalidOperationException("unable to match algorithm"); + } + } + } +} \ No newline at end of file diff --git a/crypto/src/crypto/util/CipherKeyGeneratorFactory.cs b/crypto/src/crypto/util/CipherKeyGeneratorFactory.cs new file mode 100644 index 000000000..7a24a01a8 --- /dev/null +++ b/crypto/src/crypto/util/CipherKeyGeneratorFactory.cs @@ -0,0 +1,101 @@ +using System; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Kisa; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Ntt; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Utilities +{ + public class CipherKeyGeneratorFactory + { + + /** + * Create a key generator for the passed in Object Identifier. + * + * @param algorithm the Object Identifier indicating the algorithn the generator is for. + * @param random a source of random to initialise the generator with. + * @return an initialised CipherKeyGenerator. + * @throws IllegalArgumentException if the algorithm cannot be identified. + */ + public static CipherKeyGenerator CreateKeyGenerator(DerObjectIdentifier algorithm, SecureRandom random) + + { + if (NistObjectIdentifiers.IdAes128Cbc.Equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (NistObjectIdentifiers.IdAes192Cbc.Equals(algorithm)) + { + return createCipherKeyGenerator(random, 192); + } + else if (NistObjectIdentifiers.IdAes256Cbc.Equals(algorithm)) + { + return createCipherKeyGenerator(random, 256); + } + else if (PkcsObjectIdentifiers.DesEde3Cbc.Equals(algorithm)) + { + DesEdeKeyGenerator keyGen = new DesEdeKeyGenerator(); + + keyGen.Init(new KeyGenerationParameters(random, 192)); + + return keyGen; + } + else if (NttObjectIdentifiers.IdCamellia128Cbc.Equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (NttObjectIdentifiers.IdCamellia192Cbc.Equals(algorithm)) + { + return createCipherKeyGenerator(random, 192); + } + else if (NttObjectIdentifiers.IdCamellia256Cbc.Equals(algorithm)) + { + return createCipherKeyGenerator(random, 256); + } + else if (KisaObjectIdentifiers.IdSeedCbc.Equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (AlgorithmIdentifierFactory.CAST5_CBC.Equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (OiwObjectIdentifiers.DesCbc.Equals(algorithm)) + { + DesKeyGenerator keyGen = new DesKeyGenerator(); + + keyGen.Init(new KeyGenerationParameters(random, 64)); + + return keyGen; + } + else if (PkcsObjectIdentifiers.Rc4.Equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (PkcsObjectIdentifiers.RC2Cbc.Equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else + { + throw new InvalidOperationException("cannot recognise cipher: " + algorithm); + } + } + + + + + private static CipherKeyGenerator createCipherKeyGenerator(SecureRandom random, int keySize) + { + CipherKeyGenerator keyGen = new CipherKeyGenerator(); + + keyGen.Init(new KeyGenerationParameters(random, keySize)); + + return keyGen; + } + } +} \ No newline at end of file diff --git a/crypto/test/src/crmf/test/CrmfTest.cs b/crypto/test/src/crmf/test/CrmfTest.cs new file mode 100644 index 000000000..caff0e664 --- /dev/null +++ b/crypto/test/src/crmf/test/CrmfTest.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections; +using NUnit.Core; +using NUnit.Framework; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Crmf; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Cmp.Tests; +using Org.BouncyCastle.Cms; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Operators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Pkcs; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Crmf.Tests +{ + [TestFixture] + public class CrmfTest : SimpleTest + { + + + public override string Name => "CRMF Tests"; + + + public override void PerformTest() + { + TestFromJVM(); + TestBasicMessage(); + TestBasicMessageWithArchiveControl(); + TestBasicMessageWithArchiveControlJVMGenerated(); + } + + [Test] + public void TestFromJVM() + { + var pubKey = PublicKeyFactory.CreateKey(Hex.Decode( + "305c300d06092a864886f70d0101010500034b003048024100bbb3f6a5031fbb1feedbfed7584a4f6321ccdc16b9526b0f6e31859328db35a6ec420a98e14fb3bcf192004b1aa6fc9269410204785cc01317232feb545a7b410203010001")); + var privKey = PrivateKeyFactory.CreateKey(Hex.Decode("30820153020100300d06092a864886f70d01010105000482013d30820139020100024100bbb3f6a5031fbb1feedbfed7584a4f6321ccdc16b9526b0f6e31859328db35a6ec420a98e14fb3bcf192004b1aa6fc9269410204785cc01317232feb545a7b41020301000102400093b384b9021c4cd59888e956cb1e653e736833235315b0e938116da19a9276b1ea1fe33da580a497313f08eb3e7c14627508a4284be04ea3e6ba8cb4b0a5c9022100e2fe0d9f35bfd7ecf196227e5e915a2464478ea7033c6dff4ce6a02961759a49022100d3b093770745dfea42c5c5c31f1a6b797a60dfb5503ae60f70b864452c4a193902203cc761c65b91feb3070cf8377602dd6c191dbfe8a04931fac6108a9a09ea7f61022071bb2a5f06af49cfc8340d3df995ee2c03cdcc22d389f15456511abdf73f9031022065bc10d43192cb3131c53be18a0d41a060d4e0a3324a47e3eb4bf720e1b46b10")); + + var rawMsg = Hex.Decode("3081cc30760201013071a511300f310d300b0603550403130454657374a65c300d06092a864886f70d0101010500034b003048024100bbb3f6a5031fbb1feedbfed7584a4f6321ccdc16b9526b0f6e31859328db35a6ec420a98e14fb3bcf192004b1aa6fc9269410204785cc01317232feb545a7b410203010001a152300d06092a864886f70d01010505000341003120cdb58edfef4a2e1a4bfe96b972007c1d1c949221d266efe28b45ba036b9d534f5dca261dce8f21e134d97e55c3bd76d1460781fd9703f8f9907d1f036c20"); + + var msg = new CertificateRequestMessage(rawMsg); + IsTrue("Pop Valid",msg.IsValidSigningKeyPop(new Asn1VerifierFactoryProvider(pubKey))); + + // + // Vandalize message to check for failure. + // + + rawMsg[7] ^= 1; + msg = new CertificateRequestMessage(rawMsg); + + IsTrue("Pop Verified Vandalized Message!", !msg.IsValidSigningKeyPop(new Asn1VerifierFactoryProvider(pubKey))); + + } + + + + [Test] + public void TestBasicMessage() + { + var rsaKeyPairGenerator = new RsaKeyPairGenerator(); + rsaKeyPairGenerator.Init(new RsaKeyGenerationParameters(BigInteger.ValueOf(65537), new SecureRandom(), 2048, 100)); + var rsaKeyPair = rsaKeyPairGenerator.GenerateKeyPair(); + + var certReqBuild = new CertificateRequestMessageBuilder(BigInteger.One); + + certReqBuild.SetSubject(new X509Name("CN=Test")) + .SetPublicKey(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(rsaKeyPair.Public)) + .SetProofOfPossessionSignKeySigner(new Asn1SignatureFactory("SHA1WithRSA", rsaKeyPair.Private)); + + var certificateRequestMessage = certReqBuild.Build(); + + IsTrue("Signing Key Pop Valid",certificateRequestMessage.IsValidSigningKeyPop(new Asn1VerifierFactoryProvider(rsaKeyPair.Public))); + IsTrue(certificateRequestMessage.GetCertTemplate().Subject.Equivalent(new X509Name("CN=Test"))); + IsTrue(certificateRequestMessage.GetCertTemplate().PublicKey.Equals(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(rsaKeyPair.Public))); + } + + [Test] + public void TestBasicMessageWithArchiveControl() + { + var rsaKeyPairGenerator = new RsaKeyPairGenerator(); + rsaKeyPairGenerator.Init(new RsaKeyGenerationParameters(BigInteger.ValueOf(65537), new SecureRandom(), 2048, 100)); + var rsaKeyPair = rsaKeyPairGenerator.GenerateKeyPair(); + + var tcb = new TestCertBuilder() + { + PublicKey = rsaKeyPair.Public, + Subject = new X509Name("CN=Test"), + Issuer = new X509Name("CN=Test"), + NotBefore = DateTime.UtcNow.AddDays(-1), + NotAfter = DateTime.UtcNow.AddDays(1), + SignatureAlgorithm = "Sha1WithRSAEncryption" + }; + + var cert = tcb.Build(rsaKeyPair.Private); + + var publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(rsaKeyPair.Public); + var privateInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(rsaKeyPair.Private); + + + var certificateRequestMessageBuilder = new CertificateRequestMessageBuilder(BigInteger.One); + certificateRequestMessageBuilder.SetSubject(new X509Name("CN=Test")); + certificateRequestMessageBuilder.SetPublicKey(publicKeyInfo); + + certificateRequestMessageBuilder.AddControl( + new PKIArchiveControlBuilder(privateInfo, new GeneralName(new X509Name("CN=Test"))) + .AddRecipientGenerator(new KeyTransRecipientInfoGenerator() + { + RecipientCert = cert, + SubjectKeyIdentifier = (DerOctetString)SubjectKeyIdentifier.CreateSha1KeyIdentifier(publicKeyInfo).ToAsn1Object() + }).Build(new CmsContentEncryptorBuilder(NistObjectIdentifiers.IdAes128Cbc) + .Build()) + ); + + var msg = certificateRequestMessageBuilder.Build(); + + IsTrue(Arrays.AreEqual(msg.GetCertTemplate().Subject.GetEncoded(), new X509Name("CN=Test").GetEncoded())); + IsTrue(Arrays.AreEqual(msg.GetCertTemplate().PublicKey.GetEncoded(),publicKeyInfo.GetEncoded())); + + checkCertReqMsgWithArchiveControl(rsaKeyPair,msg); + checkCertReqMsgWithArchiveControl(rsaKeyPair, new CertificateRequestMessage(msg.GetEncoded())); + + } + + [Test] + public void TestBasicMessageWithArchiveControlJVMGenerated() + { + AsymmetricKeyParameter publicKey = PublicKeyFactory.CreateKey( + Hex.Decode("305c300d06092a864886f70d0101010500034b003048024100a9a94b7b98dc3daf8cac032a14bd4510832b0e007edbdafc065e328645a35828b8185cdbf73ed495c88436b11a9322965595d2e4c1dd63c3c4d41812f876b3070203010001")); + AsymmetricKeyParameter privateKey = PrivateKeyFactory.CreateKey( + Hex.Decode("30820154020100300d06092a864886f70d01010105000482013e3082013a020100024100a9a94b7b98dc3daf8cac032a14bd4510832b0e007edbdafc065e328645a35828b8185cdbf73ed495c88436b11a9322965595d2e4c1dd63c3c4d41812f876b307020301000102400831deacfe21a9331902d7f648e1297c563196b00c70971fb439098cb5c1618925bdbac4c66b30f8956660220f326f51e5a1725ce690165154fb62fa14497265022100e54943be1b4951e127f6e79c5ab333cba4b0fff0b5e59328d6393ba98dc0e6c3022100bd6da58ce195146a1d3825ec2a622cf4962da653096bea87fbd9a94db266a66d0221008948bcceeef78f97089ec53ed0efcb6b7b489f7638f32491a6f2cdce4f99d89102204eb1b066d8883054ed12985e863506ec0d3fa5ab356cc99ff876b228ff0639f9022024049aaf39bf9a0ddfbd4caee277d0a9f07d075faae12571176a5c0ca40415c0")); + + CertificateRequestMessage msg = new CertificateRequestMessage( + Hex.Decode("308202af308202ab0201013071a511300f310d300b0603550403130454657374a65c300d06092a864886f70d0101010500034b003048024100a9a94b7b98dc3daf8cac032a14bd4510832b0e007edbdafc065e328645a35828b8185cdbf73ed495c88436b11a9322965595d2e4c1dd63c3c4d41812f876b3070203010001308202313082022d06092b0601050507050104a082021ea082021a0201003171306f0201003019300f310d300b06035504030c04546573740206016859de5806300d06092a864886f70d0101010500044066f1a72f808908af784b83c07895276104d7c4caaee6090212ce5b27517aec510425b784352b5342c999f844b8796286f10a59807e290f06aa39f8cba86dd6bf308201a0060b2a864886f70d0109100115301d060960864801650304010204104aceaa277cc7974ea2a775ff9db6062580820170c648e70c25c4789d2ff4ed398e5536efb45d2dd8ba76a628ad30bf9596a18337afc0f596f0c18e05fb3fa9944ed9691dae1d9b327b5bbafaaa63efb0e22d675811c27bfb023b80184325fd4b67b3b9e41bf43c5583a86433b230e09a34b61397ddff0eadf10c883fc1f01860e2a56ab4002dcc4d4925c53e09dde0b99928fdf602bce544722155cebd8816e91a411a99feea07695774cd8883034022d57f64e9cd3383c3125c48db2936b7395a22b17910be1f2c0b8650bdb5bd752ffc40fcd30169e5ae3a4ac7ad9cc850e9c17bbcf8e1a1898d0d8be19145c484467b8f1124657a5e08c10fc67416274990cc16d55c9fb76c265dd436b7e803425892297f1a08e4fab8e178874b2b3bf9c749693d609db208e9a3ebbddd26cd6a1b33c0201532170dc6c303e7ac0c42ba0bc54dfb928b228842b6bb08d8dc411d262dabf140a8b5a5c67ea486c1877a2fc000981d54cf2decaf1cfeebcf83134992b09a2b1fe9e02da25b874604b5d8bbd609875ba8")); + + AsymmetricCipherKeyPair rsaKeyPair = new AsymmetricCipherKeyPair(publicKey,privateKey); + + + SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey); + + + Console.WriteLine(msg.GetCertTemplate().Subject.Equivalent(new X509Name("CN=Test"))); + + IsTrue(msg.GetCertTemplate().Subject.Equivalent(new X509Name("CN=Test"))); + IsTrue(Arrays.AreEqual(msg.GetCertTemplate().PublicKey.GetEncoded(), publicKeyInfo.GetEncoded())); + + checkCertReqMsgWithArchiveControl(rsaKeyPair, msg); + checkCertReqMsgWithArchiveControl(rsaKeyPair, new CertificateRequestMessage(msg.GetEncoded())); + + checkCertReqMsgWithArchiveControl(rsaKeyPair,msg); + } + + private void checkCertReqMsgWithArchiveControl(AsymmetricCipherKeyPair kp, CertificateRequestMessage certReqMessage) + { + var archiveControl = + (PkiArchiveControl) certReqMessage.GetControl(CrmfObjectIdentifiers.id_regCtrl_pkiArchiveOptions); + IsEquals("Archive type", PkiArchiveControl.encryptedPrivKey, archiveControl.ArchiveType); + + IsTrue(archiveControl.EnvelopedData); + RecipientInformationStore recips = archiveControl.GetEnvelopedData().GetRecipientInfos(); + + ArrayList collection = (ArrayList)recips.GetRecipients(); + + IsTrue(collection.Count == 1); + KeyTransRecipientInformation info = (KeyTransRecipientInformation)collection[0]; + + EncKeyWithID encKeyWithId = EncKeyWithID.GetInstance(info.GetContent(kp.Private)); + + IsTrue(encKeyWithId.HasIdentifier); + IsTrue(!encKeyWithId.IsIdentifierUtf8String); // GeneralName at this point. + + + IsTrue("Name", X509Name.GetInstance(GeneralName.GetInstance(encKeyWithId.Identifier).Name).Equivalent(new X509Name("CN=Test"))); + + PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(kp.Private); + IsTrue("Private Key", Arrays.AreEqual(privateKeyInfo.GetEncoded(), encKeyWithId.PrivateKey.GetEncoded())); + + } + + } +} \ No newline at end of file |