Path: blob/master/src/jdk.crypto.ec/share/classes/sun/security/ec/ed/EdDSASignature.java
41162 views
/*1* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.ec.ed;2627import sun.security.ec.point.AffinePoint;2829import java.io.ByteArrayOutputStream;30import java.security.AlgorithmParameters;31import java.security.InvalidAlgorithmParameterException;32import java.security.InvalidKeyException;33import java.security.InvalidParameterException;34import java.security.NoSuchAlgorithmException;35import java.security.PrivateKey;36import java.security.ProviderException;37import java.security.PublicKey;38import java.security.SecureRandom;39import java.security.SignatureException;40import java.security.SignatureSpi;41import java.security.interfaces.EdECPrivateKey;42import java.security.interfaces.EdECPublicKey;43import java.security.spec.AlgorithmParameterSpec;44import java.security.spec.EdDSAParameterSpec;45import java.security.spec.NamedParameterSpec;46import java.util.function.Function;4748public class EdDSASignature extends SignatureSpi {4950private interface MessageAccumulator {51void add(byte b);52void add(byte[] data, int off, int len);53byte[] getMessage();54}5556private static class DigestAccumulator implements MessageAccumulator {57private final EdDSAParameters.Digester digester;5859DigestAccumulator(EdDSAParameters.Digester digester) {60this.digester = digester;61}6263@Override64public void add(byte b) {65digester.update(b);66}67@Override68public void add(byte[] data, int off, int len) {69digester.update(data, off, len);70}71@Override72public byte[] getMessage() {73return digester.digest();74}75}7677private static class MemoryAccumulator implements MessageAccumulator {78ByteArrayOutputStream message = new ByteArrayOutputStream();7980@Override81public void add(byte b) {82message.write(b);83}84@Override85public void add(byte[] data, int off, int len) {86message.write(data, off, len);87}88@Override89public byte[] getMessage() {90return message.toByteArray();91}92}9394private byte[] privateKey;95private AffinePoint publicKeyPoint;96private byte[] publicKeyBytes;97private EdDSAOperations ops;98private EdDSAParameters lockedParams = null;99private MessageAccumulator message = null;100private EdDSAParameterSpec sigParams = new EdDSAParameterSpec(false);101102public EdDSASignature() {103// do nothing104}105106EdDSASignature(NamedParameterSpec paramSpec) {107lockedParams = EdDSAParameters.get(ProviderException::new, paramSpec);108}109110@Override111protected void engineInitVerify(PublicKey publicKey)112throws InvalidKeyException {113114if (!(publicKey instanceof EdECPublicKey)) {115throw new InvalidKeyException("Unsupported key type");116}117EdECPublicKey edKey = (EdECPublicKey) publicKey;118EdDSAParameters params = EdDSAParameters.get(119InvalidKeyException::new, edKey.getParams());120121initImpl(params);122this.privateKey = null;123this.publicKeyPoint = ops.decodeAffinePoint(InvalidKeyException::new,124edKey.getPoint());125EdDSAPublicKeyImpl pubKeyImpl = new EdDSAPublicKeyImpl(params,126edKey.getPoint());127this.publicKeyBytes = pubKeyImpl.getEncodedPoint();128}129130@Override131protected void engineInitSign(PrivateKey privateKey)132throws InvalidKeyException {133engineInitSign(privateKey, null);134}135136@Override137protected void engineInitSign(PrivateKey privateKey, SecureRandom random)138throws InvalidKeyException {139140if (!(privateKey instanceof EdECPrivateKey)) {141throw new InvalidKeyException("Unsupported key type");142}143EdECPrivateKey edKey = (EdECPrivateKey) privateKey;144145initImpl(edKey.getParams());146this.privateKey = edKey.getBytes().orElseThrow(147() -> new InvalidKeyException("No private key value"));148this.publicKeyPoint = null;149this.publicKeyBytes = null;150}151152private153<T extends Throwable>154void checkLockedParams(Function<String, T> exception,155EdDSAParameters params) throws T {156if (lockedParams != null && lockedParams != params) {157throw exception.apply("Parameters must be " +158lockedParams.getName());159}160}161162private void ensureMessageInit() throws SignatureException {163if (message == null) {164initMessage();165}166}167168private void initMessage() throws SignatureException {169if (this.ops == null) {170throw new SignatureException("not initialized");171}172EdDSAParameters params = ops.getParameters();173174if (sigParams.isPrehash()) {175this.message = new DigestAccumulator(params.createDigester(64));176} else {177this.message = new MemoryAccumulator();178}179}180181@Override182protected void engineUpdate(byte b) throws SignatureException {183ensureMessageInit();184this.message.add(b);185}186187@Override188protected void engineUpdate(byte[] b, int off, int len)189throws SignatureException {190191ensureMessageInit();192this.message.add(b, off, len);193}194195@Override196protected byte[] engineSign() throws SignatureException {197if (privateKey == null) {198throw new SignatureException("Missing private key");199}200ensureMessageInit();201byte[] result = ops.sign(this.sigParams, this.privateKey,202message.getMessage());203message = null;204return result;205}206207@Override208protected boolean engineVerify(byte[] sigBytes) throws SignatureException {209if (publicKeyBytes == null) {210throw new SignatureException("Missing publicKey");211}212if (message == null) {213return false;214}215boolean result = ops.verify(this.sigParams, this.publicKeyPoint,216this.publicKeyBytes, message.getMessage(), sigBytes);217message = null;218return result;219}220221private void initImpl(EdDSAParameters params) throws InvalidKeyException {222checkLockedParams(InvalidKeyException::new, params);223224try {225this.ops = new EdDSAOperations(params);226} catch (NoSuchAlgorithmException ex) {227throw new ProviderException(ex);228}229// message is (re)set to null230// it will be initialized on first update231this.message = null;232}233234private void initImpl(NamedParameterSpec paramSpec)235throws InvalidKeyException {236237EdDSAParameters params = EdDSAParameters.get(238InvalidKeyException::new, paramSpec);239initImpl(params);240}241242@Deprecated243@Override244protected Object engineGetParameter(String param)245throws InvalidParameterException {246throw new UnsupportedOperationException("getParameter() not supported");247}248249@Deprecated250@Override251protected void engineSetParameter(String param, Object value)252throws InvalidParameterException {253254throw new UnsupportedOperationException("setParameter() not supported");255}256257@Override258protected void engineSetParameter(AlgorithmParameterSpec params)259throws InvalidAlgorithmParameterException {260261// by convention, ignore null parameters262if (params == null) {263return;264}265266if (params instanceof EdDSAParameterSpec) {267if (message != null) {268// sign/verify in progress269throw new InvalidParameterException("Cannot change signature " +270"parameters during operation");271}272EdDSAParameterSpec edDsaParams = (EdDSAParameterSpec) params;273checkContextLength(edDsaParams);274275this.sigParams = edDsaParams;276} else {277throw new InvalidAlgorithmParameterException(278"Only EdDSAParameterSpec supported");279}280}281282private static void checkContextLength(EdDSAParameterSpec edDsaParams)283throws InvalidAlgorithmParameterException {284285if (edDsaParams.getContext().isPresent()) {286byte[] context = edDsaParams.getContext().get();287if (context.length > 255) {288throw new InvalidAlgorithmParameterException(289"Context is longer than 255 bytes");290}291}292}293294// There is no RFC-defined ASN.1 for prehash and context (RFC 8410)295@Override296protected AlgorithmParameters engineGetParameters() {297return null;298}299300public static class Ed25519 extends EdDSASignature {301302public Ed25519() {303super(NamedParameterSpec.ED25519);304}305}306307public static class Ed448 extends EdDSASignature {308309public Ed448() {310super(NamedParameterSpec.ED448);311}312}313}314315316