Skip to content

Commit bda04fc

Browse files
committed
github bcgit#478 added support for C1C3C2 mode in SM2Engine
1 parent 929db00 commit bda04fc

File tree

2 files changed

+132
-8
lines changed

2 files changed

+132
-8
lines changed

core/src/main/java/org/bouncycastle/crypto/engines/SM2Engine.java

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
1313
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
1414
import org.bouncycastle.crypto.params.ParametersWithRandom;
15-
import org.bouncycastle.math.ec.ECConstants;
1615
import org.bouncycastle.math.ec.ECFieldElement;
1716
import org.bouncycastle.math.ec.ECMultiplier;
1817
import org.bouncycastle.math.ec.ECPoint;
@@ -27,7 +26,13 @@
2726
*/
2827
public class SM2Engine
2928
{
29+
public enum Mode
30+
{
31+
C1C2C3, C1C3C2;
32+
}
33+
3034
private final Digest digest;
35+
private final Mode mode;
3136

3237
private boolean forEncryption;
3338
private ECKeyParameters ecKey;
@@ -40,9 +45,24 @@ public SM2Engine()
4045
this(new SM3Digest());
4146
}
4247

48+
public SM2Engine(Mode mode)
49+
{
50+
this(new SM3Digest(), mode);
51+
}
52+
4353
public SM2Engine(Digest digest)
4454
{
55+
this(digest, Mode.C1C2C3);
56+
}
57+
58+
public SM2Engine(Digest digest, Mode mode)
59+
{
60+
if (mode == null)
61+
{
62+
throw new IllegalArgumentException("mode cannot be NULL");
63+
}
4564
this.digest = digest;
65+
this.mode = mode;
4666
}
4767

4868
public void init(boolean forEncryption, CipherParameters param)
@@ -131,8 +151,14 @@ private byte[] encrypt(byte[] in, int inOff, int inLen)
131151
addFieldElement(digest, kPB.getAffineYCoord());
132152

133153
digest.doFinal(c3, 0);
134-
135-
return Arrays.concatenate(c1, c2, c3);
154+
155+
switch (mode)
156+
{
157+
case C1C3C2:
158+
return Arrays.concatenate(c1, c3, c2);
159+
default:
160+
return Arrays.concatenate(c1, c2, c3);
161+
}
136162
}
137163

138164
private byte[] decrypt(byte[] in, int inOff, int inLen)
@@ -152,9 +178,17 @@ private byte[] decrypt(byte[] in, int inOff, int inLen)
152178

153179
c1P = c1P.multiply(((ECPrivateKeyParameters)ecKey).getD()).normalize();
154180

155-
byte[] c2 = new byte[inLen - c1.length - digest.getDigestSize()];
181+
int digestSize = this.digest.getDigestSize();
182+
byte[] c2 = new byte[inLen - c1.length - digestSize];
156183

157-
System.arraycopy(in, inOff + c1.length, c2, 0, c2.length);
184+
if (mode == Mode.C1C3C2)
185+
{
186+
System.arraycopy(in, inOff + c1.length + digestSize, c2, 0, c2.length);
187+
}
188+
else
189+
{
190+
System.arraycopy(in, inOff + c1.length, c2, 0, c2.length);
191+
}
158192

159193
kdf(digest, c1P, c2);
160194

@@ -167,9 +201,19 @@ private byte[] decrypt(byte[] in, int inOff, int inLen)
167201
digest.doFinal(c3, 0);
168202

169203
int check = 0;
170-
for (int i = 0; i != c3.length; i++)
204+
if (mode == Mode.C1C3C2)
171205
{
172-
check |= c3[i] ^ in[inOff + c1.length + c2.length + i];
206+
for (int i = 0; i != c3.length; i++)
207+
{
208+
check |= c3[i] ^ in[inOff + c1.length + i];
209+
}
210+
}
211+
else
212+
{
213+
for (int i = 0; i != c3.length; i++)
214+
{
215+
check |= c3[i] ^ in[inOff + c1.length + c2.length + i];
216+
}
173217
}
174218

175219
Arrays.fill(c1, (byte)0);
@@ -255,7 +299,7 @@ private BigInteger nextK()
255299
{
256300
k = BigIntegers.createRandomBigInteger(qBitLength, random);
257301
}
258-
while (k.equals(ECConstants.ZERO) || k.compareTo(ecParams.getN()) >= 0);
302+
while (k.equals(BigIntegers.ZERO) || k.compareTo(ecParams.getN()) >= 0);
259303

260304
return k;
261305
}

core/src/test/java/org/bouncycastle/crypto/test/SM2EngineTest.java

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,85 @@ private void doEngineTestFp()
107107
isTrue("dec wrong", Arrays.areEqual(m, dec));
108108
}
109109

110+
private void doEngineTestFpC1C3C2()
111+
throws Exception
112+
{
113+
BigInteger SM2_ECC_P = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", 16);
114+
BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16);
115+
BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16);
116+
BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16);
117+
BigInteger SM2_ECC_H = ECConstants.ONE;
118+
BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16);
119+
BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16);
120+
121+
ECCurve curve = new ECCurve.Fp(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H);
122+
123+
ECPoint g = curve.createPoint(SM2_ECC_GX, SM2_ECC_GY);
124+
ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N);
125+
126+
ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
127+
128+
ECKeyGenerationParameters aKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0", 16));
129+
130+
keyPairGenerator.init(aKeyGenParams);
131+
132+
AsymmetricCipherKeyPair aKp = keyPairGenerator.generateKeyPair();
133+
134+
ECPublicKeyParameters aPub = (ECPublicKeyParameters)aKp.getPublic();
135+
ECPrivateKeyParameters aPriv = (ECPrivateKeyParameters)aKp.getPrivate();
136+
137+
SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
138+
139+
byte[] m = Strings.toByteArray("encryption standard");
140+
141+
sm2Engine.init(true, new ParametersWithRandom(aPub, new TestRandomBigInteger("4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F", 16)));
142+
143+
byte[] enc = sm2Engine.processBlock(m, 0, m.length);
144+
145+
isTrue("enc wrong", Arrays.areEqual(Hex.decode(
146+
"04245C26 FB68B1DD DDB12C4B 6BF9F2B6 D5FE60A3 83B0D18D 1C4144AB F17F6252" +
147+
"E776CB92 64C2A7E8 8E52B199 03FDC473 78F605E3 6811F5C0 7423A24B 84400F01" +
148+
"B8 9C3D7360 C30156FA B7C80A02" +
149+
"76712DA9 D8094A63 4B766D3A 285E0748 0653426D 650053 A89B41C4 18B0C3AA D00D886C 00286467"), enc));
150+
151+
sm2Engine.init(false, aPriv);
152+
153+
byte[] dec = sm2Engine.processBlock(enc, 0, enc.length);
154+
155+
isTrue("dec wrong", Arrays.areEqual(m, dec));
156+
157+
enc[80] = (byte)(enc[80] + 1);
158+
159+
try
160+
{
161+
sm2Engine.processBlock(enc, 0, enc.length);
162+
fail("no exception");
163+
}
164+
catch (InvalidCipherTextException e)
165+
{
166+
isTrue("wrong exception", "invalid cipher text".equals(e.getMessage()));
167+
}
168+
169+
// long message
170+
sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
171+
172+
m = new byte[4097];
173+
for (int i = 0; i != m.length; i++)
174+
{
175+
m[i] = (byte)i;
176+
}
177+
178+
sm2Engine.init(true, new ParametersWithRandom(aPub, new TestRandomBigInteger("4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F", 16)));
179+
180+
enc = sm2Engine.processBlock(m, 0, m.length);
181+
182+
sm2Engine.init(false, aPriv);
183+
184+
dec = sm2Engine.processBlock(enc, 0, enc.length);
185+
186+
isTrue("dec wrong", Arrays.areEqual(m, dec));
187+
}
188+
110189
private void doEngineTestF2m()
111190
throws Exception
112191
{
@@ -159,6 +238,7 @@ public void performTest()
159238
{
160239
doEngineTestFp();
161240
doEngineTestF2m();
241+
doEngineTestFpC1C3C2();
162242
}
163243

164244
public static void main(String[] args)

0 commit comments

Comments
 (0)