diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2021-10-15 17:10:01 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2021-10-15 17:10:01 +0700 |
commit | f84f98dcb1fff8ffdfa8a3b47708c6eb8f15c5cf (patch) | |
tree | 38160e84b7de77e8327fafddca26c1571c2d780d | |
parent | Merge checks (diff) | |
download | BouncyCastle.NET-ed25519-f84f98dcb1fff8ffdfa8a3b47708c6eb8f15c5cf.tar.xz |
Use primitive encoding for short octet strings
Diffstat (limited to '')
-rw-r--r-- | crypto/src/asn1/BerOctetString.cs | 135 | ||||
-rw-r--r-- | crypto/src/asn1/DerOctetString.cs | 7 | ||||
-rw-r--r-- | crypto/test/src/asn1/test/CMSTest.cs | 46 | ||||
-rw-r--r-- | crypto/test/src/asn1/test/PKCS12Test.cs | 23 |
4 files changed, 135 insertions, 76 deletions
diff --git a/crypto/src/asn1/BerOctetString.cs b/crypto/src/asn1/BerOctetString.cs index b092d8fb2..4855e31d1 100644 --- a/crypto/src/asn1/BerOctetString.cs +++ b/crypto/src/asn1/BerOctetString.cs @@ -9,7 +9,7 @@ namespace Org.BouncyCastle.Asn1 public class BerOctetString : DerOctetString, IEnumerable { - private static readonly int DefaultChunkSize = 1000; + private static readonly int DefaultSegmentLimit = 1000; public static BerOctetString FromSequence(Asn1Sequence seq) { @@ -17,7 +17,7 @@ namespace Org.BouncyCastle.Asn1 Asn1OctetString[] v = new Asn1OctetString[count]; for (int i = 0; i < count; ++i) { - v[i] = Asn1OctetString.GetInstance(seq[i]); + v[i] = GetInstance(seq[i]); } return new BerOctetString(v); } @@ -62,13 +62,13 @@ namespace Org.BouncyCastle.Asn1 Asn1OctetString[] v = new Asn1OctetString[count]; for (int i = 0; i < count; ++i) { - v[i] = Asn1OctetString.GetInstance(list[i]); + v[i] = GetInstance(list[i]); } return v; } - private readonly int chunkSize; - private readonly Asn1OctetString[] octs; + private readonly int segmentLimit; + private readonly Asn1OctetString[] elements; [Obsolete("Will be removed")] public BerOctetString(IEnumerable e) @@ -77,30 +77,30 @@ namespace Org.BouncyCastle.Asn1 } public BerOctetString(byte[] str) - : this(str, DefaultChunkSize) + : this(str, DefaultSegmentLimit) { } - public BerOctetString(Asn1OctetString[] octs) - : this(octs, DefaultChunkSize) + public BerOctetString(Asn1OctetString[] elements) + : this(elements, DefaultSegmentLimit) { } - public BerOctetString(byte[] str, int chunkSize) - : this(str, null, chunkSize) + public BerOctetString(byte[] str, int segmentLimit) + : this(str, null, segmentLimit) { } - public BerOctetString(Asn1OctetString[] octs, int chunkSize) - : this(FlattenOctetStrings(octs), octs, chunkSize) + public BerOctetString(Asn1OctetString[] elements, int segmentLimit) + : this(FlattenOctetStrings(elements), elements, segmentLimit) { } - private BerOctetString(byte[] str, Asn1OctetString[] octs, int chunkSize) - : base(str) + private BerOctetString(byte[] octets, Asn1OctetString[] elements, int segmentLimit) + : base(octets) { - this.octs = octs; - this.chunkSize = chunkSize; + this.elements = elements; + this.segmentLimit = segmentLimit; } /** @@ -108,10 +108,10 @@ namespace Org.BouncyCastle.Asn1 */ public IEnumerator GetEnumerator() { - if (octs == null) - return new ChunkEnumerator(str, chunkSize); + if (elements == null) + return new ChunkEnumerator(str, segmentLimit); - return octs.GetEnumerator(); + return elements.GetEnumerator(); } [Obsolete("Use GetEnumerator() instead")] @@ -120,82 +120,119 @@ namespace Org.BouncyCastle.Asn1 return GetEnumerator(); } + private bool IsConstructed + { + get { return null != elements || str.Length > segmentLimit; } + } + internal override int EncodedLength(bool withID) { throw Platform.CreateNotImplementedException("BerOctetString.EncodedLength"); + + // TODO This depends on knowing it's not DER + //if (!IsConstructed) + // return EncodedLength(withID, str.Length); + + //int totalLength = withID ? 4 : 3; + + //if (null != elements) + //{ + // for (int i = 0; i < elements.Length; ++i) + // { + // totalLength += elements[i].EncodedLength(true); + // } + //} + //else + //{ + // int fullSegments = str.Length / segmentLimit; + // totalLength += fullSegments * EncodedLength(true, segmentLimit); + + // int lastSegmentLength = str.Length - (fullSegments * segmentLimit); + // if (lastSegmentLength > 0) + // { + // totalLength += EncodedLength(true, lastSegmentLength); + // } + //} + + //return totalLength; } internal override void Encode(Asn1OutputStream asn1Out, bool withID) { - if (asn1Out.IsBer) + if (!asn1Out.IsBer || !IsConstructed) { - if (withID) - { - asn1Out.WriteByte(Asn1Tags.Constructed | Asn1Tags.OctetString); - } + base.Encode(asn1Out, withID); + return; + } - asn1Out.WriteByte(0x80); + asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.OctetString); + asn1Out.WriteByte(0x80); - foreach (Asn1OctetString oct in this) - { - oct.Encode(asn1Out, true); - } - - asn1Out.WriteByte(0x00); - asn1Out.WriteByte(0x00); + if (null != elements) + { + asn1Out.WritePrimitives(elements); } else { - base.Encode(asn1Out, withID); + int pos = 0; + while (pos < str.Length) + { + int segmentLength = System.Math.Min(str.Length - pos, segmentLimit); + Encode(asn1Out, true, str, pos, segmentLength); + pos += segmentLength; + } } + + asn1Out.WriteByte(0x00); + asn1Out.WriteByte(0x00); } private class ChunkEnumerator : IEnumerator { private readonly byte[] octets; - private readonly int chunkSize; + private readonly int segmentLimit; - private DerOctetString currentChunk = null; - private int nextChunkPos = 0; + private DerOctetString currentSegment = null; + private int nextSegmentPos = 0; - internal ChunkEnumerator(byte[] octets, int chunkSize) + internal ChunkEnumerator(byte[] octets, int segmentLimit) { this.octets = octets; - this.chunkSize = chunkSize; + this.segmentLimit = segmentLimit; } public object Current { get { - if (null == currentChunk) + if (null == currentSegment) throw new InvalidOperationException(); - return currentChunk; + return currentSegment; } } public bool MoveNext() { - if (nextChunkPos >= octets.Length) + if (nextSegmentPos >= octets.Length) { - this.currentChunk = null; + this.currentSegment = null; return false; } - int length = System.Math.Min(octets.Length - nextChunkPos, chunkSize); - byte[] chunk = new byte[length]; - Array.Copy(octets, nextChunkPos, chunk, 0, length); - this.currentChunk = new DerOctetString(chunk); - this.nextChunkPos += length; + int length = System.Math.Min(octets.Length - nextSegmentPos, segmentLimit); + byte[] segment = new byte[length]; + Array.Copy(octets, nextSegmentPos, segment, 0, length); + this.currentSegment = new DerOctetString(segment); + this.nextSegmentPos += length; return true; } public void Reset() { - this.currentChunk = null; - this.nextChunkPos = 0; + this.currentSegment = null; + this.nextSegmentPos = 0; } } } diff --git a/crypto/src/asn1/DerOctetString.cs b/crypto/src/asn1/DerOctetString.cs index bdabb8221..bcd4e7333 100644 --- a/crypto/src/asn1/DerOctetString.cs +++ b/crypto/src/asn1/DerOctetString.cs @@ -36,5 +36,10 @@ namespace Org.BouncyCastle.Asn1 { asn1Out.WriteEncodingDL(withID, Asn1Tags.OctetString, buf, off, len); } - } + + internal static int EncodedLength(bool withID, int contentsLength) + { + return Asn1OutputStream.GetLengthOfEncodingDL(withID, contentsLength); + } + } } diff --git a/crypto/test/src/asn1/test/CMSTest.cs b/crypto/test/src/asn1/test/CMSTest.cs index 1afb363af..9930830f1 100644 --- a/crypto/test/src/asn1/test/CMSTest.cs +++ b/crypto/test/src/asn1/test/CMSTest.cs @@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Asn1.Tests // // compressed data object // - private static readonly byte[] compData = Base64.Decode( + private static readonly byte[] OrigCompData = Base64.Decode( "MIAGCyqGSIb3DQEJEAEJoIAwgAIBADANBgsqhkiG9w0BCRADCDCABgkqhkiG9w0BBwGggCSABIIC" + "Hnic7ZRdb9owFIbvK/k/5PqVYPFXGK12YYyboVFASSp1vQtZGiLRACZE49/XHoUW7S/0tXP8Efux" + "fU5ivWnasml72XFb3gb5druui7ytN803M570nii7C5r8tfwR281hy/p/KSM3+jzH5s3+pbQ90xSb" @@ -72,7 +72,7 @@ namespace Org.BouncyCastle.Asn1.Tests // // signed data // - private static readonly byte[] signedData = Base64.Decode( + private static readonly byte[] OrigSignedData = Base64.Decode( "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAaCA" + "JIAEDEhlbGxvIFdvcmxkIQAAAAAAAKCCBGIwggINMIIBdqADAgECAgEBMA0GCSqG" + "SIb3DQEBBAUAMCUxFjAUBgNVBAoTDUJvdW5jeSBDYXN0bGUxCzAJBgNVBAYTAkFV" @@ -114,14 +114,10 @@ namespace Org.BouncyCastle.Asn1.Tests { try { - ContentInfo info = ContentInfo.GetInstance( - Asn1Object.FromByteArray(compData)); - CompressedData data = CompressedData.GetInstance(info.Content); - - data = new CompressedData(data.CompressionAlgorithmIdentifier, data.EncapContentInfo); - info = new ContentInfo(CmsObjectIdentifiers.CompressedData, data); + byte[] compData1 = ImplCompressionTest(OrigCompData); + byte[] compData2 = ImplCompressionTest(compData1); - if (!Arrays.AreEqual(info.GetEncoded(), compData)) + if (!Arrays.AreEqual(compData1, compData2)) { return new SimpleTestResult(false, Name + ": CMS compression failed to re-encode"); } @@ -134,7 +130,16 @@ namespace Org.BouncyCastle.Asn1.Tests } } - private ITestResult EnvelopedTest() + private byte[] ImplCompressionTest(byte[] compData) + { + ContentInfo info = ContentInfo.GetInstance(Asn1Object.FromByteArray(compData)); + CompressedData data = CompressedData.GetInstance(info.Content); + data = new CompressedData(data.CompressionAlgorithmIdentifier, data.EncapContentInfo); + info = new ContentInfo(CmsObjectIdentifiers.CompressedData, data); + return info.GetEncoded(); + } + + private ITestResult EnvelopedTest() { try { @@ -243,14 +248,10 @@ namespace Org.BouncyCastle.Asn1.Tests { try { - ContentInfo info = ContentInfo.GetInstance( - Asn1Object.FromByteArray(signedData)); - SignedData sData = SignedData.GetInstance(info.Content); - - sData = new SignedData(sData.DigestAlgorithms, sData.EncapContentInfo, sData.Certificates, sData.CRLs, sData.SignerInfos); - info = new ContentInfo(CmsObjectIdentifiers.SignedData, sData); + byte[] signedData1 = ImplSignedTest(OrigSignedData); + byte[] signedData2 = ImplSignedTest(signedData1); - if (!Arrays.AreEqual(info.GetEncoded(), signedData)) + if (!Arrays.AreEqual(signedData1, signedData2)) { return new SimpleTestResult(false, Name + ": CMS signed failed to re-encode"); } @@ -263,7 +264,16 @@ namespace Org.BouncyCastle.Asn1.Tests } } - public ITestResult Perform() + private byte[] ImplSignedTest(byte[] signedData) + { + ContentInfo info = ContentInfo.GetInstance(Asn1Object.FromByteArray(signedData)); + SignedData sData = SignedData.GetInstance(info.Content); + sData = new SignedData(sData.DigestAlgorithms, sData.EncapContentInfo, sData.Certificates, sData.CRLs, sData.SignerInfos); + info = new ContentInfo(CmsObjectIdentifiers.SignedData, sData); + return info.GetEncoded(); + } + + public ITestResult Perform() { ITestResult res = CompressionTest(); diff --git a/crypto/test/src/asn1/test/PKCS12Test.cs b/crypto/test/src/asn1/test/PKCS12Test.cs index 5e4748728..eae61de46 100644 --- a/crypto/test/src/asn1/test/PKCS12Test.cs +++ b/crypto/test/src/asn1/test/PKCS12Test.cs @@ -113,6 +113,20 @@ namespace Org.BouncyCastle.Asn1.Tests + "AgFkAAA="); public override void PerformTest() + { + byte[] pfxEncoding1 = ImplTest(pkcs12); + byte[] pfxEncoding2 = ImplTest(pfxEncoding1); + + // + // comparison test + // + if (!Arrays.AreEqual(pfxEncoding1, pfxEncoding2)) + { + Fail("failed comparison test"); + } + } + + private byte[] ImplTest(byte[] pkcs12) { Pfx bag = Pfx.GetInstance(pkcs12); ContentInfo info = bag.AuthSafe; @@ -178,14 +192,7 @@ namespace Org.BouncyCastle.Asn1.Tests bag = new Pfx(info, mData); - // - // comparison test - // - byte[] pfxEncoding = bag.GetEncoded(); - if (!Arrays.AreEqual(pfxEncoding, pkcs12)) - { - Fail("Failed comparison test"); - } + return bag.GetEncoded(); } public override string Name |