Skip to content

Commit cb4a98a

Browse files
rsandelldaniel-beck
andcommitted
[SECURITY-3404]
Co-authored-by: Daniel Beck <daniel-beck@users.noreply.github.com>
1 parent dcf1d64 commit cb4a98a

File tree

5 files changed

+134
-2
lines changed

5 files changed

+134
-2
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ Refer to our [contribution guidelines](https://github.com/jenkinsci/.github/blob
1313

1414
## LICENSE
1515

16-
Licensed under MIT, see [LICENSE](LICENSE.md)
16+
Plugin Licensed under MIT, see [LICENSE](LICENSE.md)
1717

18+
ed25519-java licensed under CC0 1.0 Universal, see [LICENSE](https://github.com/str4d/ed25519-java/blob/7c26a6312c2d2e887210930698706103e0f2da7d/LICENSE.txt)

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
<url>https://github.com/jenkinsci/eddsa-api-plugin</url>
2727
</scm>
2828
<properties>
29-
<revision>0.3.0</revision>
29+
<revision>0.3.0.1</revision>
3030
<changelist>999999-SNAPSHOT</changelist>
3131
<jenkins.version>2.479.1</jenkins.version>
3232
<spotless.check.skip>false</spotless.check.skip>

src/main/java/net/i2p/crypto/eddsa/EdDSAEngine.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
package net.i2p.crypto.eddsa;
1313

1414
import java.io.ByteArrayOutputStream;
15+
import java.math.BigInteger;
1516
import java.nio.ByteBuffer;
1617
import java.security.InvalidAlgorithmParameterException;
1718
import java.security.InvalidKeyException;
@@ -28,6 +29,7 @@
2829
import net.i2p.crypto.eddsa.math.Curve;
2930
import net.i2p.crypto.eddsa.math.GroupElement;
3031
import net.i2p.crypto.eddsa.math.ScalarOps;
32+
import net.i2p.crypto.eddsa.math.bigint.BigIntegerLittleEndianEncoding;
3133

3234
/**
3335
* Signing and verification for EdDSA.
@@ -272,6 +274,9 @@ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
272274
}
273275
}
274276

277+
private static final BigInteger BL_ORDER =
278+
new BigInteger("2").pow(252).add(new BigInteger("27742317777372353535851937790883648493"));
279+
275280
private boolean x_engineVerify(byte[] sigBytes) throws SignatureException {
276281
Curve curve = key.getParams().getCurve();
277282
int b = curve.getField().getb();
@@ -301,6 +306,10 @@ private boolean x_engineVerify(byte[] sigBytes) throws SignatureException {
301306
h = key.getParams().getScalarOps().reduce(h);
302307

303308
byte[] Sbyte = Arrays.copyOfRange(sigBytes, b / 8, b / 4);
309+
// RFC 8032
310+
BigInteger Sbigint = (new BigIntegerLittleEndianEncoding()).toBigInteger(Sbyte);
311+
if (Sbigint.compareTo(BL_ORDER) >= 0) return false;
312+
304313
// R = SB - H(Rbar,Abar,M)A
305314
GroupElement R = key.getParams()
306315
.getB()
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright (c) Facebook, Inc. and its affiliates.
2+
//
3+
// This source code is licensed under the APACHE 2.0 license found in
4+
// the LICENSE file in the root directory of the source tree
5+
// https://github.com/novifinancial/ed25519-speccheck/blob/main/scripts/ed25519-java/src/main/java/EncodingUtils.java
6+
7+
package io.jenkins.plugins.eddsa_api.security3404;
8+
9+
/** Encoding utils for cryptographic material. **/
10+
public class EncodingUtils {
11+
12+
/** Get X509 format of a compressed Edwards point (public key). **/
13+
public static byte[] compressedEd25519PublicKeyToX509(byte[] compressedPublicKey) {
14+
int totlen = 12 + compressedPublicKey.length;
15+
byte[] rv = new byte[totlen];
16+
int idx = 0;
17+
// sequence
18+
rv[idx++] = 0x30;
19+
rv[idx++] = (byte) (totlen - 2);
20+
// Algorithm Identifier
21+
// sequence
22+
rv[idx++] = 0x30;
23+
rv[idx++] = 5;
24+
// OID
25+
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb540809%28v=vs.85%29.aspx
26+
rv[idx++] = 0x06;
27+
rv[idx++] = 3;
28+
rv[idx++] = 43;
29+
rv[idx++] = 101;
30+
rv[idx++] = (byte) 112;
31+
// params - absent
32+
// the key
33+
rv[idx++] = 0x03; // bit string
34+
rv[idx++] = (byte) (1 + compressedPublicKey.length);
35+
rv[idx++] = 0; // number of trailing unused bits
36+
System.arraycopy(compressedPublicKey, 0, rv, idx, compressedPublicKey.length);
37+
return rv;
38+
}
39+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package io.jenkins.plugins.eddsa_api.security3404;
2+
3+
import static org.hamcrest.CoreMatchers.is;
4+
import static org.hamcrest.MatcherAssert.assertThat;
5+
6+
import java.security.MessageDigest;
7+
import java.security.NoSuchAlgorithmException;
8+
import java.security.spec.InvalidKeySpecException;
9+
import java.security.spec.X509EncodedKeySpec;
10+
import java.util.List;
11+
import net.i2p.crypto.eddsa.EdDSAEngine;
12+
import net.i2p.crypto.eddsa.EdDSAPublicKey;
13+
import net.i2p.crypto.eddsa.Utils;
14+
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
15+
import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec;
16+
import org.junit.Test;
17+
import org.junit.runner.RunWith;
18+
import org.junit.runners.Parameterized;
19+
20+
@RunWith(Parameterized.class)
21+
public class Security3404Test {
22+
private final String messageHex;
23+
private final String publicKeyHex;
24+
private final String signatureHex;
25+
26+
private static final EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
27+
28+
@Parameterized.Parameters
29+
public static List<List<String>> parameters() {
30+
// See https://eprint.iacr.org/2020/1244.pdf Table 6 c), as well as Section 5.1 for an explanation that these
31+
// signatures are supposed to fail to ensure SUF-CMA property
32+
return List.of(
33+
List.of(
34+
"85e241a07d148b41e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec40",
35+
"442aad9f089ad9e14647b1ef9099a1ff4798d78589e66f28eca69c11f582a623",
36+
"e96f66be976d82e60150baecff9906684aebb1ef181f67a7189ac78ea23b6c0e547f7690a0e2ddcd04d87dbc3490dc19b3b3052f7ff0538cb68afb369ba3a514"),
37+
List.of(
38+
"85e241a07d148b41e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec40",
39+
"442aad9f089ad9e14647b1ef9099a1ff4798d78589e66f28eca69c11f582a623",
40+
"8ce5b96c8f26d0ab6c47958c9e68b937104cd36e13c33566acd2fe8d38aa19427e71f98a473474f2f13f06f97c20d58cc3f54b8bd0d272f42b695dd7e89a8c22"));
41+
}
42+
43+
@Test
44+
public void testCases5And6() throws NoSuchAlgorithmException {
45+
assertThat(verify_i2p(), is(false));
46+
}
47+
48+
public Security3404Test(List<String> parameters) {
49+
messageHex = parameters.get(0);
50+
publicKeyHex = parameters.get(1);
51+
signatureHex = parameters.get(2);
52+
}
53+
54+
/**
55+
* Return EdDSAPublicKey object from the hex representation of the compressed Edwards public key point.
56+
**/
57+
// Code used under Apache 2.0 license from
58+
// https://github.com/novifinancial/ed25519-speccheck/blob/main/scripts/ed25519-java/src/main/java/Ed25519TestCase.java
59+
private EdDSAPublicKey decodePublicKey() throws InvalidKeySpecException {
60+
byte[] pk = Utils.hexToBytes(this.publicKeyHex);
61+
byte[] x509pk = EncodingUtils.compressedEd25519PublicKeyToX509(pk);
62+
X509EncodedKeySpec encoded = new X509EncodedKeySpec(x509pk);
63+
return new EdDSAPublicKey(encoded);
64+
}
65+
66+
/**
67+
* Pure Ed25519 signature verification using the i2p lib, it returns false if it fails or if an exception occurs).
68+
**/
69+
// Code used under Apache 2.0 license from
70+
// https://github.com/novifinancial/ed25519-speccheck/blob/main/scripts/ed25519-java/src/main/java/Ed25519TestCase.java
71+
public boolean verify_i2p() {
72+
try {
73+
EdDSAPublicKey publicKey = decodePublicKey();
74+
byte[] messageBytes = Utils.hexToBytes(this.messageHex);
75+
byte[] signatureBytes = Utils.hexToBytes(this.signatureHex);
76+
EdDSAEngine sgr = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
77+
sgr.initVerify(publicKey);
78+
return sgr.verifyOneShot(messageBytes, signatureBytes);
79+
} catch (Exception e) {
80+
return false;
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)