/
githubmirror
/
jdk22
Обзор
Документация
Войти
/
githubmirror
/
jdk22
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/java.base/share/classes/sun/security/ec/ed/EdDSAOperations.java
282 строки
10 KB
Anthony Scarpino
8308398: Move SunEC crypto provider into java.base
17 июл 2023, 20:38
17 июл 2023, 20:38
e737968
Код
Авторство
О чём код?
/* * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.ec.ed; import sun.security.ec.point.AffinePoint; import sun.security.ec.point.Point; import sun.security.util.ArrayUtil; import sun.security.util.math.IntegerFieldModuloP; import sun.security.util.math.IntegerModuloP; import sun.security.util.math.MutableIntegerModuloP; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.SignatureException; import java.security.spec.EdDSAParameterSpec; import java.security.spec.EdECPoint; import java.util.Arrays; import java.util.function.Function; /* * A class containing the operations of the EdDSA signature scheme. The * parameters include an object that performs the elliptic curve point * arithmetic, and EdDSAOperations uses this object to construct the signing * and verification operations. */ public class EdDSAOperations { private final EdDSAParameters params; public EdDSAOperations(EdDSAParameters params) throws NoSuchAlgorithmException { this.params = params; } public EdDSAParameters getParameters() { return params; } public byte[] generatePrivate(SecureRandom random) { byte[] result = new byte[params.getKeyLength()]; random.nextBytes(result); return result; } public EdECPoint computePublic(byte[] privateKey) { byte[] privateKeyHash = params.digest(privateKey); int byteLength = privateKeyHash.length / 2; byte[] s = Arrays.copyOf(privateKeyHash, byteLength); prune(s); IntegerModuloP fieldS = params.getOrderField().getElement(s); fieldS.asByteArray(s); Point A = params.getEdOperations().basePointMultiply(s); return asEdECPoint(A.asAffine()); } private static EdECPoint asEdECPoint(AffinePoint p) { return new EdECPoint(p.getX().asBigInteger().testBit(0), p.getY().asBigInteger()); } public byte[] sign(EdDSAParameterSpec sigParams, byte[] privateKey, byte[] message) { byte[] privateKeyHash = params.digest(privateKey); int byteLength = privateKeyHash.length / 2; byte[] s = Arrays.copyOf(privateKeyHash, byteLength); prune(s); IntegerModuloP sElem = params.getOrderField().getElement(s); sElem.asByteArray(s); Point A = params.getEdOperations().basePointMultiply(s); byte[] prefix = Arrays.copyOfRange(privateKeyHash, privateKeyHash.length / 2, privateKeyHash.length); byte[] dom = params.dom(sigParams); byte[] r = params.digest(dom, prefix, message); // reduce r modulo the order IntegerModuloP fieldR = params.getOrderField().getElement(r); r = new byte[params.getKeyLength()]; fieldR.asByteArray(r); Point R = params.getEdOperations().basePointMultiply(r); byte[] encodedR = encode(byteLength, R); byte[] encodedA = encode(byteLength, A); byte[] k = params.digest(dom, encodedR, encodedA, message); // S computation is in group-order field IntegerFieldModuloP subField = params.getOrderField(); IntegerModuloP kElem = subField.getElement(k); IntegerModuloP rElem = subField.getElement(r); MutableIntegerModuloP S = kElem.mutable().setProduct(sElem); S.setSum(rElem); byte[] sArr = S.asByteArray(byteLength); byte[] rArr = encode(byteLength, R); byte[] result = new byte[byteLength * 2]; System.arraycopy(rArr, 0, result, 0, byteLength); System.arraycopy(sArr, 0, result, byteLength, byteLength); return result; } public boolean verify(EdDSAParameterSpec sigParams, AffinePoint affineA, byte[] publicKey, byte[] message, byte[] signature) throws SignatureException { if (signature == null) { throw new SignatureException("signature was null"); } if (params.getKeyLength() * 2 != signature.length) { throw new SignatureException("signature length invalid"); } byte[] encR = Arrays.copyOf(signature, signature.length / 2); byte[] encS = Arrays.copyOfRange(signature, signature.length / 2, signature.length); // reject s if it is too large ArrayUtil.reverse(encS); BigInteger bigS = new BigInteger(1, encS); if (bigS.compareTo(params.getOrderField().getSize()) >= 0) { throw new SignatureException("s is too large"); } ArrayUtil.reverse(encS); byte[] dom = params.dom(sigParams); AffinePoint affineR = decodeAffinePoint(SignatureException::new, encR); byte[] k = params.digest(dom, encR, publicKey, message); // reduce k to improve performance of multiply IntegerFieldModuloP subField = params.getOrderField(); IntegerModuloP kElem = subField.getElement(k); k = kElem.asByteArray(k.length / 2); Point pointR = params.getEdOperations().of(affineR); Point pointA = params.getEdOperations().of(affineA); EdECOperations edOps = params.getEdOperations(); Point lhs = edOps.basePointMultiply(encS); Point rhs = edOps.setSum(edOps.setProduct(pointA.mutable(), k), pointR.mutable()); return lhs.affineEquals(rhs); } public boolean verify(EdDSAParameterSpec sigParams, byte[] publicKey, byte[] message, byte[] signature) throws InvalidKeyException, SignatureException { AffinePoint affineA = decodeAffinePoint(InvalidKeyException::new, publicKey); return verify(sigParams, affineA, publicKey, message, signature); } public <T extends Throwable> AffinePoint decodeAffinePoint(Function<String, T> exception, byte[] arr) throws T { if (arr.length != params.getKeyLength()) { throw exception.apply("incorrect length"); } arr = arr.clone(); int xLSB = (0xFF & arr[arr.length - 1]) >>> 7; arr[arr.length - 1] &= 0x7F; int yLength = (params.getBits() + 7) >> 3; IntegerModuloP y = params.getField().getElement(arr, 0, yLength, (byte) 0); // reject non-canonical y values ArrayUtil.reverse(arr); BigInteger bigY = new BigInteger(1, arr); if (bigY.compareTo(params.getField().getSize()) >= 0) { throw exception.apply("y value is too large"); } return params.getEdOperations().decodeAffinePoint(exception, xLSB, y); } public <T extends Throwable> AffinePoint decodeAffinePoint(Function<String, T> exception, EdECPoint point) throws T { // reject non-canonical y values if (point.getY().compareTo(params.getField().getSize()) >= 0) { throw exception.apply("y value is too large"); } int xLSB = point.isXOdd() ? 1 : 0; IntegerModuloP y = params.getField().getElement(point.getY()); return params.getEdOperations().decodeAffinePoint(exception, xLSB, y); } /** * Mask off the high order bits of an encoded integer in an array. The * array is modified in place. * * @param arr an array containing an encoded integer * @param bits the number of bits to keep * @return the number, in range [0,8], of bits kept in the highest byte */ private static int maskHighOrder(byte[] arr, int bits) { int lastByteIndex = arr.length - 1; int bitsDiff = arr.length * 8 - bits; int highBits = 8 - bitsDiff; byte msbMaskOff = (byte) ((1 << highBits) - 1); arr[lastByteIndex] &= msbMaskOff; return highBits; } /** * Prune an encoded scalar value by modifying it in place. The extra * high-order bits are masked off, the highest valid bit it set, and the * number is rounded down to a multiple of the co-factor. * * @param k an encoded scalar value * @param bits the number of bits in the scalar * @param logCofactor the base-2 logarithm of the co-factor */ private static void prune(byte[] k, int bits, int logCofactor) { int lastByteIndex = k.length - 1; // mask off unused high-order bits int highBits = maskHighOrder(k, bits); // set the highest bit if (highBits == 0) { k[lastByteIndex - 1] |= (byte) 0x80; } else { byte msbMaskOn = (byte) (1 << (highBits - 1)); k[lastByteIndex] |= msbMaskOn; } // round down to a multiple of the co-factor byte lsbMaskOff = (byte) (0xFF << logCofactor); k[0] &= lsbMaskOff; } void prune(byte[] arr) { prune(arr, params.getBits(), params.getLogCofactor()); } private static byte[] encode(int length, Point p) { return encode(length, p.asAffine()); } private static byte[] encode(int length, AffinePoint p) { byte[] result = p.getY().asByteArray(length); int xLSB = p.getX().asByteArray(1)[0] & 0x01; result[result.length - 1] |= (byte) (xLSB << 7); return result; } }