Skip to content

Commit 9fde4fa

Browse files
committed
Merge branch 'main' of gitlab.cryptoworkshop.com:root/bc-java
2 parents 043caa5 + 011e041 commit 9fde4fa

File tree

10 files changed

+184
-287
lines changed

10 files changed

+184
-287
lines changed

core/src/main/java/org/bouncycastle/asn1/x9/KeySpecificInfo.java

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package org.bouncycastle.asn1.x9;
22

3-
import java.util.Enumeration;
4-
53
import org.bouncycastle.asn1.ASN1Object;
64
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
75
import org.bouncycastle.asn1.ASN1OctetString;
86
import org.bouncycastle.asn1.ASN1Primitive;
97
import org.bouncycastle.asn1.ASN1Sequence;
8+
import org.bouncycastle.asn1.ASN1TaggedObject;
109
import org.bouncycastle.asn1.DERSequence;
1110

1211
/**
@@ -22,23 +21,6 @@
2221
public class KeySpecificInfo
2322
extends ASN1Object
2423
{
25-
private ASN1ObjectIdentifier algorithm;
26-
private ASN1OctetString counter;
27-
28-
/**
29-
* Base constructor.
30-
*
31-
* @param algorithm algorithm identifier for the CEK.
32-
* @param counter initial counter value for key derivation.
33-
*/
34-
public KeySpecificInfo(
35-
ASN1ObjectIdentifier algorithm,
36-
ASN1OctetString counter)
37-
{
38-
this.algorithm = algorithm;
39-
this.counter = counter;
40-
}
41-
4224
/**
4325
* Return a KeySpecificInfo object from the passed in object.
4426
*
@@ -59,13 +41,50 @@ else if (obj != null)
5941
return null;
6042
}
6143

62-
private KeySpecificInfo(
63-
ASN1Sequence seq)
44+
public static KeySpecificInfo getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit)
45+
{
46+
return new KeySpecificInfo(ASN1Sequence.getInstance(taggedObject, declaredExplicit));
47+
}
48+
49+
public static KeySpecificInfo getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit)
50+
{
51+
return new KeySpecificInfo(ASN1Sequence.getTagged(taggedObject, declaredExplicit));
52+
}
53+
54+
private final ASN1ObjectIdentifier algorithm;
55+
private final ASN1OctetString counter;
56+
57+
private KeySpecificInfo(ASN1Sequence seq)
6458
{
65-
Enumeration e = seq.getObjects();
59+
int count = seq.size();
60+
if (count != 2)
61+
{
62+
throw new IllegalArgumentException("Bad sequence size: " + count);
63+
}
64+
65+
this.algorithm = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
66+
this.counter = ASN1OctetString.getInstance(seq.getObjectAt(1));
67+
}
6668

67-
algorithm = (ASN1ObjectIdentifier)e.nextElement();
68-
counter = (ASN1OctetString)e.nextElement();
69+
/**
70+
* Base constructor.
71+
*
72+
* @param algorithm algorithm identifier for the CEK.
73+
* @param counter initial counter value for key derivation.
74+
*/
75+
public KeySpecificInfo(ASN1ObjectIdentifier algorithm, ASN1OctetString counter)
76+
{
77+
if (algorithm == null)
78+
{
79+
throw new NullPointerException("'algorithm' cannot be null");
80+
}
81+
if (counter == null)
82+
{
83+
throw new NullPointerException("'counter' cannot be null");
84+
}
85+
86+
this.algorithm = algorithm;
87+
this.counter = counter;
6988
}
7089

7190
/**

core/src/main/java/org/bouncycastle/asn1/x9/OtherInfo.java

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package org.bouncycastle.asn1.x9;
22

3-
import java.util.Enumeration;
4-
53
import org.bouncycastle.asn1.ASN1EncodableVector;
64
import org.bouncycastle.asn1.ASN1Object;
75
import org.bouncycastle.asn1.ASN1OctetString;
@@ -25,20 +23,6 @@
2523
public class OtherInfo
2624
extends ASN1Object
2725
{
28-
private KeySpecificInfo keyInfo;
29-
private ASN1OctetString partyAInfo;
30-
private ASN1OctetString suppPubInfo;
31-
32-
public OtherInfo(
33-
KeySpecificInfo keyInfo,
34-
ASN1OctetString partyAInfo,
35-
ASN1OctetString suppPubInfo)
36-
{
37-
this.keyInfo = keyInfo;
38-
this.partyAInfo = partyAInfo;
39-
this.suppPubInfo = suppPubInfo;
40-
}
41-
4226
/**
4327
* Return a OtherInfo object from the passed in object.
4428
*
@@ -59,26 +43,66 @@ else if (obj != null)
5943
return null;
6044
}
6145

62-
private OtherInfo(
63-
ASN1Sequence seq)
46+
public static OtherInfo getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit)
6447
{
65-
Enumeration e = seq.getObjects();
48+
return new OtherInfo(ASN1Sequence.getInstance(taggedObject, declaredExplicit));
49+
}
6650

67-
keyInfo = KeySpecificInfo.getInstance(e.nextElement());
51+
public static OtherInfo getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit)
52+
{
53+
return new OtherInfo(ASN1Sequence.getTagged(taggedObject, declaredExplicit));
54+
}
55+
56+
private final KeySpecificInfo keyInfo;
57+
private final ASN1OctetString partyAInfo;
58+
private final ASN1OctetString suppPubInfo;
6859

69-
while (e.hasMoreElements())
60+
private OtherInfo(ASN1Sequence seq)
61+
{
62+
int count = seq.size(), pos = 0;
63+
if (count < 2 || count > 3)
7064
{
71-
ASN1TaggedObject o = (ASN1TaggedObject)e.nextElement();
65+
throw new IllegalArgumentException("Bad sequence size: " + count);
66+
}
7267

73-
if (o.hasContextTag(0))
74-
{
75-
partyAInfo = (ASN1OctetString)o.getExplicitBaseObject();
76-
}
77-
else if (o.hasContextTag(2))
68+
this.keyInfo = KeySpecificInfo.getInstance(seq.getObjectAt(pos++));
69+
70+
// partyAInfo [0] OCTET STRING OPTIONAL
71+
ASN1OctetString partyAInfo = null;
72+
if (pos < count)
73+
{
74+
ASN1TaggedObject tag0 = ASN1TaggedObject.getContextOptional(seq.getObjectAt(pos), 0);
75+
if (tag0 != null)
7876
{
79-
suppPubInfo = (ASN1OctetString)o.getExplicitBaseObject();
77+
pos++;
78+
partyAInfo = ASN1OctetString.getTagged(tag0, true);
8079
}
8180
}
81+
this.partyAInfo = partyAInfo;
82+
83+
ASN1TaggedObject tag2 = ASN1TaggedObject.getContextInstance(seq.getObjectAt(pos++), 2);
84+
this.suppPubInfo = ASN1OctetString.getTagged(tag2, true);
85+
86+
if (pos != count)
87+
{
88+
throw new IllegalArgumentException("Unexpected elements in sequence");
89+
}
90+
}
91+
92+
public OtherInfo(KeySpecificInfo keyInfo, ASN1OctetString partyAInfo, ASN1OctetString suppPubInfo)
93+
{
94+
if (keyInfo == null)
95+
{
96+
throw new NullPointerException("'keyInfo' cannot be null");
97+
}
98+
if (suppPubInfo == null)
99+
{
100+
throw new NullPointerException("'suppPubInfo' cannot be null");
101+
}
102+
103+
this.keyInfo = keyInfo;
104+
this.partyAInfo = partyAInfo;
105+
this.suppPubInfo = suppPubInfo;
82106
}
83107

84108
/**

core/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java

Lines changed: 34 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@
22

33
import java.io.IOException;
44

5-
import org.bouncycastle.asn1.ASN1EncodableVector;
65
import org.bouncycastle.asn1.ASN1Encoding;
76
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
7+
import org.bouncycastle.asn1.ASN1OctetString;
88
import org.bouncycastle.asn1.DEROctetString;
9-
import org.bouncycastle.asn1.DERSequence;
10-
import org.bouncycastle.asn1.DERTaggedObject;
9+
import org.bouncycastle.asn1.x9.KeySpecificInfo;
10+
import org.bouncycastle.asn1.x9.OtherInfo;
1111
import org.bouncycastle.crypto.DataLengthException;
1212
import org.bouncycastle.crypto.DerivationFunction;
1313
import org.bouncycastle.crypto.DerivationParameters;
1414
import org.bouncycastle.crypto.Digest;
1515
import org.bouncycastle.crypto.OutputLengthException;
16+
import org.bouncycastle.crypto.io.DigestOutputStream;
1617
import org.bouncycastle.util.Pack;
1718

1819
/**
@@ -26,10 +27,9 @@ public class DHKEKGenerator
2627
private ASN1ObjectIdentifier algorithm;
2728
private int keySize;
2829
private byte[] z;
29-
private byte[] partyAInfo;
30+
private byte[] extraInfo;
3031

31-
public DHKEKGenerator(
32-
Digest digest)
32+
public DHKEKGenerator(Digest digest)
3333
{
3434
this.digest = digest;
3535
}
@@ -41,7 +41,7 @@ public void init(DerivationParameters param)
4141
this.algorithm = params.getAlgorithm();
4242
this.keySize = params.getKeySize();
4343
this.z = params.getZ();
44-
this.partyAInfo = params.getExtraInfo();
44+
this.extraInfo = params.getExtraInfo();
4545
}
4646

4747
public Digest getDigest()
@@ -57,76 +57,56 @@ public int generateBytes(byte[] out, int outOff, int len)
5757
throw new OutputLengthException("output buffer too small");
5858
}
5959

60-
long oBytes = len;
61-
int outLen = digest.getDigestSize();
60+
digest.reset();
61+
62+
int outputLength = len;
63+
int digestSize = digest.getDigestSize();
6264

63-
//
64-
// this is at odds with the standard implementation, the
65-
// maximum value should be hBits * (2^32 - 1) where hBits
66-
// is the digest output size in bits. We can't have an
67-
// array with a long index at the moment...
68-
//
69-
if (oBytes > ((2L << 32) - 1))
65+
// NOTE: This limit isn't reachable for current array lengths
66+
if (outputLength > ((1L << 32) - 1) * digestSize)
7067
{
7168
throw new IllegalArgumentException("Output length too large");
7269
}
7370

74-
int cThreshold = (int)((oBytes + outLen - 1) / outLen);
71+
int counter32 = 0;
72+
byte[] counterOctets = new byte[4];
7573

76-
byte[] dig = new byte[digest.getDigestSize()];
74+
ASN1OctetString counter = DEROctetString.withContents(counterOctets);
75+
KeySpecificInfo keyInfo = new KeySpecificInfo(algorithm, counter);
76+
ASN1OctetString partyAInfo = DEROctetString.withContentsOptional(extraInfo);
77+
ASN1OctetString suppPubInfo = DEROctetString.withContents(Pack.intToBigEndian(keySize));
78+
OtherInfo otherInfo = new OtherInfo(keyInfo, partyAInfo, suppPubInfo);
7779

78-
int counter = 1;
80+
DigestOutputStream digestSink = new DigestOutputStream(digest);
7981

80-
for (int i = 0; i < cThreshold; i++)
82+
while (len > 0)
8183
{
8284
digest.update(z, 0, z.length);
8385

84-
// OtherInfo
85-
ASN1EncodableVector v1 = new ASN1EncodableVector();
86-
// KeySpecificInfo
87-
ASN1EncodableVector v2 = new ASN1EncodableVector();
88-
89-
v2.add(algorithm);
90-
v2.add(new DEROctetString(Pack.intToBigEndian(counter)));
91-
92-
v1.add(new DERSequence(v2));
93-
94-
if (partyAInfo != null)
95-
{
96-
v1.add(new DERTaggedObject(true, 0, new DEROctetString(partyAInfo)));
97-
}
98-
99-
v1.add(new DERTaggedObject(true, 2, new DEROctetString(Pack.intToBigEndian(keySize))));
100-
10186
try
10287
{
103-
byte[] other = new DERSequence(v1).getEncoded(ASN1Encoding.DER);
104-
105-
digest.update(other, 0, other.length);
88+
// NOTE: Modify counterOctets in-situ since counter is private to this method
89+
Pack.intToBigEndian(++counter32, counterOctets);
90+
otherInfo.encodeTo(digestSink, ASN1Encoding.DER);
10691
}
10792
catch (IOException e)
10893
{
10994
throw new IllegalArgumentException("unable to encode parameter info: " + e.getMessage());
11095
}
11196

112-
digest.doFinal(dig, 0);
113-
114-
if (len > outLen)
97+
if (len < digestSize)
11598
{
116-
System.arraycopy(dig, 0, out, outOff, outLen);
117-
outOff += outLen;
118-
len -= outLen;
119-
}
120-
else
121-
{
122-
System.arraycopy(dig, 0, out, outOff, len);
99+
byte[] tmp = new byte[digestSize];
100+
digest.doFinal(tmp, 0);
101+
System.arraycopy(tmp, 0, out, outOff, len);
102+
break;
123103
}
124104

125-
counter++;
105+
digest.doFinal(out, outOff);
106+
outOff += digestSize;
107+
len -= digestSize;
126108
}
127109

128-
digest.reset();
129-
130-
return (int)oBytes;
110+
return outputLength;
131111
}
132112
}

core/src/main/java/org/bouncycastle/crypto/agreement/kdf/ECDHKEKGenerator.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
import java.io.IOException;
44

5-
import org.bouncycastle.asn1.ASN1EncodableVector;
65
import org.bouncycastle.asn1.ASN1Encoding;
76
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
7+
import org.bouncycastle.asn1.ASN1OctetString;
8+
import org.bouncycastle.asn1.ASN1Sequence;
89
import org.bouncycastle.asn1.DERNull;
910
import org.bouncycastle.asn1.DEROctetString;
1011
import org.bouncycastle.asn1.DERSequence;
@@ -58,16 +59,18 @@ public int generateBytes(byte[] out, int outOff, int len)
5859
throw new DataLengthException("output buffer too small");
5960
}
6061

61-
// TODO Create an ASN.1 class for this (RFC3278)
62-
// ECC-CMS-SharedInfo
63-
ASN1EncodableVector v = new ASN1EncodableVector();
62+
AlgorithmIdentifier keyInfo = new AlgorithmIdentifier(algorithm, DERNull.INSTANCE);
63+
ASN1OctetString suppPubInfo = DEROctetString.withContents(Pack.intToBigEndian(keySize));
6464

65-
v.add(new AlgorithmIdentifier(algorithm, DERNull.INSTANCE));
66-
v.add(new DERTaggedObject(true, 2, new DEROctetString(Pack.intToBigEndian(keySize))));
65+
// TODO org.bouncycastle.asn1.cms.ecc.ECCCMSSharedInfo exists, but is located in the 'util' jar.
66+
// TODO Should the optional DHKDFParameters.getExtraInfo be used for ECCCMSSharedInfo.entityUInfo?
67+
ASN1Sequence eccCMSSharedInfo = new DERSequence(keyInfo, new DERTaggedObject(2, suppPubInfo));
6768

6869
try
6970
{
70-
kdf.init(new KDFParameters(z, new DERSequence(v).getEncoded(ASN1Encoding.DER)));
71+
byte[] iv = eccCMSSharedInfo.getEncoded(ASN1Encoding.DER);
72+
73+
kdf.init(new KDFParameters(z, iv));
7174
}
7275
catch (IOException e)
7376
{

0 commit comments

Comments
 (0)