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 static com.google.common.truth.Truth.assertThat; 20 import static org.junit.Assert.assertThrows; 21 22 import com.google.crypto.tink.aead.ChaCha20Poly1305Key; 23 import com.google.crypto.tink.internal.KeyTester; 24 import com.google.crypto.tink.subtle.Random; 25 import com.google.crypto.tink.util.Bytes; 26 import com.google.crypto.tink.util.SecretBytes; 27 import java.security.GeneralSecurityException; 28 import org.junit.Test; 29 import org.junit.experimental.theories.DataPoints; 30 import org.junit.experimental.theories.FromDataPoints; 31 import org.junit.experimental.theories.Theories; 32 import org.junit.experimental.theories.Theory; 33 import org.junit.runner.RunWith; 34 35 @RunWith(Theories.class) 36 public final class Ed25519PublicKeyTest { 37 38 @DataPoints("requireIdVariants") 39 public static final Ed25519Parameters.Variant[] REQUIRE_ID_VARIANTS = 40 new Ed25519Parameters.Variant[] { 41 Ed25519Parameters.Variant.TINK, 42 Ed25519Parameters.Variant.CRUNCHY, 43 Ed25519Parameters.Variant.LEGACY 44 }; 45 46 @Test buildNoPrefixVariantAndGetProperties()47 public void buildNoPrefixVariantAndGetProperties() throws Exception { 48 Bytes keyBytes = Bytes.copyFrom(Random.randBytes(32)); 49 50 Ed25519PublicKey key = Ed25519PublicKey.create(keyBytes); 51 52 assertThat(key.getParameters()).isEqualTo(Ed25519Parameters.create()); 53 assertThat(key.getPublicKeyBytes()).isEqualTo(keyBytes); 54 assertThat(key.getOutputPrefix()).isEqualTo(Bytes.copyFrom(new byte[] {})); 55 assertThat(key.getIdRequirementOrNull()).isNull(); 56 } 57 58 @Test buildNoPrefixVariantExplicitAndGetProperties()59 public void buildNoPrefixVariantExplicitAndGetProperties() throws Exception { 60 Bytes keyBytes = Bytes.copyFrom(Random.randBytes(32)); 61 62 Ed25519PublicKey key = 63 Ed25519PublicKey.create( 64 Ed25519Parameters.Variant.NO_PREFIX, keyBytes, /* idRequirement= */ null); 65 66 assertThat(key.getParameters()).isEqualTo(Ed25519Parameters.create()); 67 assertThat(key.getPublicKeyBytes()).isEqualTo(keyBytes); 68 assertThat(key.getOutputPrefix()).isEqualTo(Bytes.copyFrom(new byte[] {})); 69 assertThat(key.getIdRequirementOrNull()).isNull(); 70 } 71 72 @Test buildTinkVariantAndGetProperties()73 public void buildTinkVariantAndGetProperties() throws Exception { 74 Bytes keyBytes = Bytes.copyFrom(Random.randBytes(32)); 75 76 Ed25519PublicKey key = 77 Ed25519PublicKey.create( 78 Ed25519Parameters.Variant.TINK, keyBytes, /* idRequirement= */ 0x0708090a); 79 80 assertThat(key.getParameters()) 81 .isEqualTo(Ed25519Parameters.create(Ed25519Parameters.Variant.TINK)); 82 assertThat(key.getPublicKeyBytes()).isEqualTo(keyBytes); 83 assertThat(key.getOutputPrefix()) 84 .isEqualTo(Bytes.copyFrom(new byte[] {0x01, 0x07, 0x08, 0x09, 0x0a})); 85 assertThat(key.getIdRequirementOrNull()).isEqualTo(0x708090a); 86 } 87 88 @Test buildCrunchyVariantAndGetProperties()89 public void buildCrunchyVariantAndGetProperties() throws Exception { 90 Bytes keyBytes = Bytes.copyFrom(Random.randBytes(32)); 91 92 Ed25519PublicKey key = 93 Ed25519PublicKey.create( 94 Ed25519Parameters.Variant.CRUNCHY, keyBytes, /* idRequirement= */ 0x0708090a); 95 96 assertThat(key.getParameters()) 97 .isEqualTo(Ed25519Parameters.create(Ed25519Parameters.Variant.CRUNCHY)); 98 assertThat(key.getPublicKeyBytes()).isEqualTo(keyBytes); 99 assertThat(key.getOutputPrefix()) 100 .isEqualTo(Bytes.copyFrom(new byte[] {0x00, 0x07, 0x08, 0x09, 0x0a})); 101 assertThat(key.getIdRequirementOrNull()).isEqualTo(0x708090a); 102 } 103 104 @Test buildLegacyVariantAndGetProperties()105 public void buildLegacyVariantAndGetProperties() throws Exception { 106 Bytes keyBytes = Bytes.copyFrom(Random.randBytes(32)); 107 108 Ed25519PublicKey key = 109 Ed25519PublicKey.create( 110 Ed25519Parameters.Variant.LEGACY, keyBytes, /* idRequirement= */ 0x0708090a); 111 112 assertThat(key.getParameters()) 113 .isEqualTo(Ed25519Parameters.create(Ed25519Parameters.Variant.LEGACY)); 114 assertThat(key.getPublicKeyBytes()).isEqualTo(keyBytes); 115 assertThat(key.getOutputPrefix()) 116 .isEqualTo(Bytes.copyFrom(new byte[] {0x00, 0x07, 0x08, 0x09, 0x0a})); 117 assertThat(key.getIdRequirementOrNull()).isEqualTo(0x708090a); 118 } 119 120 @Theory requireIdButIdIsNotSet_fails( @romDataPoints"requireIdVariants") Ed25519Parameters.Variant variant)121 public void requireIdButIdIsNotSet_fails( 122 @FromDataPoints("requireIdVariants") Ed25519Parameters.Variant variant) throws Exception { 123 Bytes keyBytes = Bytes.copyFrom(Random.randBytes(32)); 124 125 assertThrows( 126 GeneralSecurityException.class, 127 () -> Ed25519PublicKey.create(variant, keyBytes, /* idRequirement= */ null)); 128 } 129 130 @Test doesNotRequireIdButIdIsSet_fails()131 public void doesNotRequireIdButIdIsSet_fails() throws Exception { 132 Bytes keyBytes = Bytes.copyFrom(Random.randBytes(32)); 133 134 assertThrows( 135 GeneralSecurityException.class, 136 () -> 137 Ed25519PublicKey.create( 138 Ed25519Parameters.Variant.NO_PREFIX, keyBytes, /* idRequirement= */ 1115)); 139 } 140 141 @Test invalidKeySize()142 public void invalidKeySize() throws Exception { 143 Bytes keyBytes = Bytes.copyFrom(Random.randBytes(64)); 144 145 assertThrows(GeneralSecurityException.class, () -> Ed25519PublicKey.create(keyBytes)); 146 } 147 148 @Test testEqualities()149 public void testEqualities() throws Exception { 150 Bytes keyBytes = Bytes.copyFrom(Random.randBytes(32)); 151 Bytes keyBytesCopy = Bytes.copyFrom(keyBytes.toByteArray()); 152 Bytes keyBytesDiff = Bytes.copyFrom(Random.randBytes(32)); 153 154 new KeyTester() 155 .addEqualityGroup( 156 "No prefix, keyBytes", 157 Ed25519PublicKey.create(keyBytes), 158 Ed25519PublicKey.create( 159 Ed25519Parameters.Variant.NO_PREFIX, keyBytes, /* idRequirement= */ null), 160 Ed25519PublicKey.create( 161 Ed25519Parameters.Variant.NO_PREFIX, keyBytesCopy, /* idRequirement= */ null)) 162 .addEqualityGroup( 163 "No prefix, different key bytes", 164 Ed25519PublicKey.create( 165 Ed25519Parameters.Variant.NO_PREFIX, keyBytesDiff, /* idRequirement= */ null)) 166 .addEqualityGroup( 167 "Tink with key id 1907, keyBytes", 168 Ed25519PublicKey.create( 169 Ed25519Parameters.Variant.TINK, keyBytes, /* idRequirement= */ 1907), 170 Ed25519PublicKey.create( 171 Ed25519Parameters.Variant.TINK, keyBytesCopy, /* idRequirement= */ 1907)) 172 .addEqualityGroup( 173 "Tink with key id 1908, keyBytes", 174 Ed25519PublicKey.create( 175 Ed25519Parameters.Variant.TINK, keyBytes, /* idRequirement= */ 1908)) 176 .addEqualityGroup( 177 "Crunchy with key id 1907, keyBytes", 178 Ed25519PublicKey.create( 179 Ed25519Parameters.Variant.CRUNCHY, keyBytes, /* idRequirement= */ 1907)) 180 .addEqualityGroup( 181 "Legacy with key id 1908, keyBytes", 182 Ed25519PublicKey.create( 183 Ed25519Parameters.Variant.LEGACY, keyBytes, /* idRequirement= */ 1907)) 184 .doTests(); 185 } 186 187 @Test testDifferentKeyTypesEquality_fails()188 public void testDifferentKeyTypesEquality_fails() throws Exception { 189 SecretBytes secretKeyBytes = SecretBytes.randomBytes(32); 190 Bytes publicKeyBytes = Bytes.copyFrom(Random.randBytes(32)); 191 192 Ed25519PublicKey ed25519Key = Ed25519PublicKey.create(publicKeyBytes); 193 ChaCha20Poly1305Key chaCha20Poly1305Key = ChaCha20Poly1305Key.create(secretKeyBytes); 194 195 assertThat(ed25519Key.equalsKey(chaCha20Poly1305Key)).isFalse(); 196 } 197 } 198