验证 ECPoint 在给定 x y 坐标和曲线名称的 EllipticCurve 对象上是否有效
Verify that ECPoint is valid on EllipticCurve object given x y coordinates and curve name
给定 public 键的 x 和 y 坐标以及曲线名称,我需要确定这些坐标是否代表曲线上的有效点。如果是,则测试通过。如果否,则测试失败。
到目前为止我的代码是:
String curve = (String) testGroupHeaders.get("curve");
String curve_num = curve.split("-")[1];
String specName = "secp" + curve_num + "r1";
String qx = (String) testsData.get("qx");
String qy = (String) testsData.get("qy");
BigInteger x = new BigInteger(qx, 16);
BigInteger y = new BigInteger(qy, 16);
ECPoint ecPoint = new ECPoint(x, y);
if (ecPoint.equals(ECPoint.POINT_INFINITY)) {
testResultsObject.put("testPassed", false);
} else {
try {
AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
parameters.init(new ECGenParameterSpec(specName));
ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class);
EllipticCurve ellCurve = ecParameters.getCurve();
ECPublicKeySpec keySpec = new ECPublicKeySpec(ecPoint, ecParameters);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
ECPublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(keySpec);
testResultsObject.put("testPassed", true);
} catch (Exception e) {
System.out.println(e);
testResultsObject.put("testPassed", false);
}
我希望如果点数无效,public 密钥的构造将失败,但这段代码仍然会导致在输入已知无效点时通过测试。
如有任何帮助,我们将不胜感激。
我发现这个问题 How to determine whether EC Point is on curve? 答案很模糊:
“可能有更直接的方法,但如果您有 EllipticCurve 对象,您始终可以将点的坐标代入曲线方程。”
这可能是一个潜在的解决方案,但我不确定如何实施它。我试过了:
EllipticCurve ellC = publicKey.getParams().getCurve();
本以为曲线构建失败,可惜还是成功了
请注意,BouncyCastle 不适合我,我必须使用 java.security 提供商。
我也找到了这个答案Elliptic curve point
但我也没能从中得到任何东西。
编辑
好的,在根据上面最后一个链接的答案中的 Bouncy Castle 代码改编后,我非常接近这段代码:
EllipticCurve ellCurve = ecParameters.getCurve();
BigInteger a = ellCurve.getA();
BigInteger b = ellCurve.getB();
ECField ecField = ellCurve.getField();
ECFieldFp fp = (ECFieldFp) ecField;
BigInteger p = ((ECFieldFp) ecField).getP();
BigInteger rhs = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
BigInteger lhs = y.multiply(y).mod(p);
System.out.println(rhs);
System.out.println(lhs);
这适用于大多数情况,除了 secp521r1 的特殊情况:
{
"tcId": 8,
"qx": "02ED3613D77D9096DC0545F3EEC44270762BF52E63044D29FC880556114F4FC176DBE20A9BC717C58FA63BB3308D3136355A072704C0B8BE9A6B3CFFFE36467722C0",
"qy": "00E857AE0D11FB1B79AC9531980A3E3BD1AC9E457E39A107D0AF5C9E09F2D6243F31C697C74CFD6A80F1CA5FCDA5950754DCC8724B9B21ED3A6705EBA1B9D2926B8F"
},
当我应用上面的代码并将 lhs 与 rhs 进行比较时,我得到了相同的输出,这表明这是曲线上的一个有效点。
rhs: 1634177850809752323211745106139613474061093186782816308703279366414782386677365518237753355552098931968864191666289807321598625802278923850729659158219971712
lhs: 1634177850809752323211745106139613474061093186782816308703279366414782386677365518237753355552098931968864191666289807321598625802278923850729659158219971712
所以必须有一个我遗漏的不同检查表明这是失败的。
找出答案,post稍后将它写在这里供我自己或遇到此问题的任何其他人使用。除了主要 post 中的编辑之外,我还缺少检查仿射 x 和 y 是否在 [0, p-1] 范围内。参考:https://neilmadden.blog/2017/05/17/so-how-do-you-validate-nist-ecdh-public-keys/
这是没有充气城堡的完整工作代码:
String curve = (String) testGroupHeaders.get("curve");
String curve_num = curve.split("-")[1];
String specName = "secp" + curve_num + "r1";
JSONArray tests = (JSONArray) testGroupHeaders.get("tests");
JSONArray testResultsArray = new JSONArray();
for (int k = 0; k < tests.size(); k++){
JSONObject testResultsObject = new JSONObject();
JSONObject testsData = (JSONObject) tests.get(k);
long tcId = (long) testsData.get("tcId");
testResultsObject.put("tcId", tcId);
String qx = (String) testsData.get("qx");
String qy = (String) testsData.get("qy");
BigInteger x = new BigInteger(qx, 16);
BigInteger y = new BigInteger(qy, 16);
ECPoint ecPoint = new ECPoint(x, y);
if (ecPoint.equals(ECPoint.POINT_INFINITY)) {
testResultsObject.put("testPassed", false);
} else {
try {
AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
parameters.init(new ECGenParameterSpec(specName));
ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class);
EllipticCurve ellCurve = ecParameters.getCurve();
BigInteger a = ellCurve.getA();
BigInteger b = ellCurve.getB();
ECField ecField = ellCurve.getField();
BigInteger p = ((ECFieldFp) ecField).getP();
BigInteger rhs = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
BigInteger lhs = y.multiply(y).mod(p);
// Do this part to try and generate an exception
ECPublicKeySpec keySpec = new ECPublicKeySpec(ecPoint, ecParameters);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
ECPublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(keySpec);
BigInteger affineX = publicKey.getW().getAffineX();
BigInteger affineY = publicKey.getW().getAffineY();
if (affineX.compareTo(BigInteger.ZERO) < 0 || affineX.compareTo(p) >= 0
|| affineY.compareTo(BigInteger.ZERO) < 0 || affineY.compareTo(p) >= 0) {
testResultsObject.put("testPassed", false);
} else {
if (rhs.equals(lhs)) {
testResultsObject.put("testPassed", true);
} else {
testResultsObject.put("testPassed", false);
}
}
} catch (Exception e) {
testResultsObject.put("testPassed", false);
}
请注意,这只是 POC 代码,可以进行大量清理 up/optimized。所有 .get 调用都来自我正在解析的 JSON 请求,因此您获取字符串 values/inputs 的方式可能会有所不同。
给定 public 键的 x 和 y 坐标以及曲线名称,我需要确定这些坐标是否代表曲线上的有效点。如果是,则测试通过。如果否,则测试失败。
到目前为止我的代码是:
String curve = (String) testGroupHeaders.get("curve");
String curve_num = curve.split("-")[1];
String specName = "secp" + curve_num + "r1";
String qx = (String) testsData.get("qx");
String qy = (String) testsData.get("qy");
BigInteger x = new BigInteger(qx, 16);
BigInteger y = new BigInteger(qy, 16);
ECPoint ecPoint = new ECPoint(x, y);
if (ecPoint.equals(ECPoint.POINT_INFINITY)) {
testResultsObject.put("testPassed", false);
} else {
try {
AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
parameters.init(new ECGenParameterSpec(specName));
ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class);
EllipticCurve ellCurve = ecParameters.getCurve();
ECPublicKeySpec keySpec = new ECPublicKeySpec(ecPoint, ecParameters);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
ECPublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(keySpec);
testResultsObject.put("testPassed", true);
} catch (Exception e) {
System.out.println(e);
testResultsObject.put("testPassed", false);
}
我希望如果点数无效,public 密钥的构造将失败,但这段代码仍然会导致在输入已知无效点时通过测试。
如有任何帮助,我们将不胜感激。
我发现这个问题 How to determine whether EC Point is on curve? 答案很模糊:
“可能有更直接的方法,但如果您有 EllipticCurve 对象,您始终可以将点的坐标代入曲线方程。”
这可能是一个潜在的解决方案,但我不确定如何实施它。我试过了:
EllipticCurve ellC = publicKey.getParams().getCurve();
本以为曲线构建失败,可惜还是成功了
请注意,BouncyCastle 不适合我,我必须使用 java.security 提供商。
我也找到了这个答案Elliptic curve point
但我也没能从中得到任何东西。
编辑
好的,在根据上面最后一个链接的答案中的 Bouncy Castle 代码改编后,我非常接近这段代码:
EllipticCurve ellCurve = ecParameters.getCurve();
BigInteger a = ellCurve.getA();
BigInteger b = ellCurve.getB();
ECField ecField = ellCurve.getField();
ECFieldFp fp = (ECFieldFp) ecField;
BigInteger p = ((ECFieldFp) ecField).getP();
BigInteger rhs = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
BigInteger lhs = y.multiply(y).mod(p);
System.out.println(rhs);
System.out.println(lhs);
这适用于大多数情况,除了 secp521r1 的特殊情况:
{
"tcId": 8,
"qx": "02ED3613D77D9096DC0545F3EEC44270762BF52E63044D29FC880556114F4FC176DBE20A9BC717C58FA63BB3308D3136355A072704C0B8BE9A6B3CFFFE36467722C0",
"qy": "00E857AE0D11FB1B79AC9531980A3E3BD1AC9E457E39A107D0AF5C9E09F2D6243F31C697C74CFD6A80F1CA5FCDA5950754DCC8724B9B21ED3A6705EBA1B9D2926B8F"
},
当我应用上面的代码并将 lhs 与 rhs 进行比较时,我得到了相同的输出,这表明这是曲线上的一个有效点。
rhs: 1634177850809752323211745106139613474061093186782816308703279366414782386677365518237753355552098931968864191666289807321598625802278923850729659158219971712
lhs: 1634177850809752323211745106139613474061093186782816308703279366414782386677365518237753355552098931968864191666289807321598625802278923850729659158219971712
所以必须有一个我遗漏的不同检查表明这是失败的。
找出答案,post稍后将它写在这里供我自己或遇到此问题的任何其他人使用。除了主要 post 中的编辑之外,我还缺少检查仿射 x 和 y 是否在 [0, p-1] 范围内。参考:https://neilmadden.blog/2017/05/17/so-how-do-you-validate-nist-ecdh-public-keys/
这是没有充气城堡的完整工作代码:
String curve = (String) testGroupHeaders.get("curve");
String curve_num = curve.split("-")[1];
String specName = "secp" + curve_num + "r1";
JSONArray tests = (JSONArray) testGroupHeaders.get("tests");
JSONArray testResultsArray = new JSONArray();
for (int k = 0; k < tests.size(); k++){
JSONObject testResultsObject = new JSONObject();
JSONObject testsData = (JSONObject) tests.get(k);
long tcId = (long) testsData.get("tcId");
testResultsObject.put("tcId", tcId);
String qx = (String) testsData.get("qx");
String qy = (String) testsData.get("qy");
BigInteger x = new BigInteger(qx, 16);
BigInteger y = new BigInteger(qy, 16);
ECPoint ecPoint = new ECPoint(x, y);
if (ecPoint.equals(ECPoint.POINT_INFINITY)) {
testResultsObject.put("testPassed", false);
} else {
try {
AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
parameters.init(new ECGenParameterSpec(specName));
ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class);
EllipticCurve ellCurve = ecParameters.getCurve();
BigInteger a = ellCurve.getA();
BigInteger b = ellCurve.getB();
ECField ecField = ellCurve.getField();
BigInteger p = ((ECFieldFp) ecField).getP();
BigInteger rhs = x.multiply(x).multiply(x).add(a.multiply(x)).add(b).mod(p);
BigInteger lhs = y.multiply(y).mod(p);
// Do this part to try and generate an exception
ECPublicKeySpec keySpec = new ECPublicKeySpec(ecPoint, ecParameters);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
ECPublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(keySpec);
BigInteger affineX = publicKey.getW().getAffineX();
BigInteger affineY = publicKey.getW().getAffineY();
if (affineX.compareTo(BigInteger.ZERO) < 0 || affineX.compareTo(p) >= 0
|| affineY.compareTo(BigInteger.ZERO) < 0 || affineY.compareTo(p) >= 0) {
testResultsObject.put("testPassed", false);
} else {
if (rhs.equals(lhs)) {
testResultsObject.put("testPassed", true);
} else {
testResultsObject.put("testPassed", false);
}
}
} catch (Exception e) {
testResultsObject.put("testPassed", false);
}
请注意,这只是 POC 代码,可以进行大量清理 up/optimized。所有 .get 调用都来自我正在解析的 JSON 请求,因此您获取字符串 values/inputs 的方式可能会有所不同。