• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16 
17 package com.google.crypto.tink.signature;
18 
19 import com.google.crypto.tink.AccessesPartialKey;
20 import com.google.crypto.tink.InsecureSecretKeyAccess;
21 import com.google.crypto.tink.Key;
22 import com.google.crypto.tink.internal.Ed25519;
23 import com.google.crypto.tink.util.SecretBytes;
24 import com.google.errorprone.annotations.Immutable;
25 import com.google.errorprone.annotations.RestrictedApi;
26 import java.security.GeneralSecurityException;
27 import java.util.Arrays;
28 
29 /** The key for computing Ed25519 signatures. */
30 @Immutable
31 public final class Ed25519PrivateKey extends SignaturePrivateKey {
32   private final Ed25519PublicKey publicKey;
33   private final SecretBytes privateKeyBytes;
34 
Ed25519PrivateKey(Ed25519PublicKey publicKey, SecretBytes privateKeyBytes)35   private Ed25519PrivateKey(Ed25519PublicKey publicKey, SecretBytes privateKeyBytes) {
36     this.publicKey = publicKey;
37     this.privateKeyBytes = privateKeyBytes;
38   }
39 
40   @AccessesPartialKey
41   @RestrictedApi(
42       explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
43       link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
44       allowedOnPath = ".*Test\\.java",
45       allowlistAnnotations = {AccessesPartialKey.class})
create(Ed25519PublicKey publicKey, SecretBytes privateKeyBytes)46   public static Ed25519PrivateKey create(Ed25519PublicKey publicKey, SecretBytes privateKeyBytes)
47       throws GeneralSecurityException {
48     if (publicKey == null) {
49       throw new GeneralSecurityException(
50           "Ed25519 key cannot be constructed without an Ed25519 public key");
51     }
52     if (privateKeyBytes.size() != 32) {
53       throw new GeneralSecurityException(
54           "Ed25519 key must be constructed with key of length 32 bytes, not "
55               + privateKeyBytes.size());
56     }
57 
58     // Validate private key based on the public key bytes.
59     byte[] publicKeyBytes = publicKey.getPublicKeyBytes().toByteArray();
60     byte[] secretSeed = privateKeyBytes.toByteArray(InsecureSecretKeyAccess.get());
61     byte[] expectedPublicKeyBytes =
62         Ed25519.scalarMultWithBaseToBytes(Ed25519.getHashedScalar(secretSeed));
63 
64     if (!Arrays.equals(publicKeyBytes, expectedPublicKeyBytes)) {
65       throw new GeneralSecurityException("Ed25519 keys mismatch");
66     }
67 
68     return new Ed25519PrivateKey(publicKey, privateKeyBytes);
69   }
70 
71   @Override
getParameters()72   public Ed25519Parameters getParameters() {
73     return publicKey.getParameters();
74   }
75 
76   @Override
getPublicKey()77   public Ed25519PublicKey getPublicKey() {
78     return publicKey;
79   }
80 
81   @RestrictedApi(
82       explanation = "Accessing parts of keys can produce unexpected incompatibilities, annotate the function with @AccessesPartialKey",
83       link = "https://developers.google.com/tink/design/access_control#accessing_partial_keys",
84       allowedOnPath = ".*Test\\.java",
85       allowlistAnnotations = {AccessesPartialKey.class})
getPrivateKeyBytes()86   public SecretBytes getPrivateKeyBytes() {
87     return privateKeyBytes;
88   }
89 
90   @Override
equalsKey(Key o)91   public boolean equalsKey(Key o) {
92     if (!(o instanceof Ed25519PrivateKey)) {
93       return false;
94     }
95     Ed25519PrivateKey that = (Ed25519PrivateKey) o;
96     return that.publicKey.equalsKey(publicKey)
97         && privateKeyBytes.equalsSecretBytes(that.privateKeyBytes);
98   }
99 }
100