1 // Copyright 2017 Google Inc. 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.subtle; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.junit.Assert.assertThrows; 21 22 import com.google.crypto.tink.PublicKeyVerify; 23 import com.google.crypto.tink.config.TinkFips; 24 import com.google.crypto.tink.signature.Ed25519PrivateKey; 25 import com.google.crypto.tink.signature.internal.testing.Ed25519TestUtil; 26 import com.google.crypto.tink.signature.internal.testing.SignatureTestVector; 27 import com.google.crypto.tink.testing.WycheproofTestUtil; 28 import com.google.gson.JsonArray; 29 import com.google.gson.JsonObject; 30 import java.security.GeneralSecurityException; 31 import java.util.ArrayList; 32 import java.util.Arrays; 33 import org.junit.Assume; 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 import org.junit.runners.JUnit4; 37 38 /** Unit tests for {@link Ed25519Verify}. */ 39 @RunWith(JUnit4.class) 40 public final class Ed25519VerifyTest { 41 @Test testVerificationWithPublicKeyLengthDifferentFrom32Byte()42 public void testVerificationWithPublicKeyLengthDifferentFrom32Byte() throws Exception { 43 Assume.assumeFalse(TinkFips.useOnlyFips()); 44 45 assertThrows( 46 IllegalArgumentException.class, 47 () -> { 48 Ed25519Verify unused = new Ed25519Verify(new byte[31]); 49 }); 50 assertThrows( 51 IllegalArgumentException.class, 52 () -> { 53 Ed25519Verify unused = new Ed25519Verify(new byte[33]); 54 }); 55 } 56 getMessage(JsonObject testcase)57 private byte[] getMessage(JsonObject testcase) throws Exception { 58 if (testcase.has("msg")) { 59 return Hex.decode(testcase.get("msg").getAsString()); 60 } else { 61 return Hex.decode(testcase.get("message").getAsString()); 62 } 63 } 64 65 @Test testVerificationWithWycheproofVectors()66 public void testVerificationWithWycheproofVectors() throws Exception { 67 Assume.assumeFalse(TinkFips.useOnlyFips()); 68 69 JsonObject json = 70 WycheproofTestUtil.readJson("../wycheproof/testvectors/eddsa_test.json"); 71 ArrayList<String> errors = new ArrayList<>(); 72 JsonArray testGroups = json.get("testGroups").getAsJsonArray(); 73 for (int i = 0; i < testGroups.size(); i++) { 74 JsonObject group = testGroups.get(i).getAsJsonObject(); 75 JsonObject key = group.get("key").getAsJsonObject(); 76 byte[] publicKey = Hex.decode(key.get("pk").getAsString()); 77 JsonArray tests = group.get("tests").getAsJsonArray(); 78 for (int j = 0; j < tests.size(); j++) { 79 JsonObject testcase = tests.get(j).getAsJsonObject(); 80 String tcId = 81 String.format("testcase %d (%s)", 82 testcase.get("tcId").getAsInt(), testcase.get("comment").getAsString()); 83 byte[] msg = getMessage(testcase); 84 byte[] sig = Hex.decode(testcase.get("sig").getAsString()); 85 String result = testcase.get("result").getAsString(); 86 Ed25519Verify verifier = new Ed25519Verify(publicKey); 87 try { 88 verifier.verify(sig, msg); 89 if (result.equals("invalid")) { 90 errors.add("FAIL " + tcId + ": accepting invalid signature"); 91 } 92 } catch (GeneralSecurityException ex) { 93 if (result.equals("valid")) { 94 errors.add( 95 "FAIL " + tcId + ": rejecting valid signature, exception: " + ex.getMessage()); 96 } 97 } 98 } 99 } 100 assertThat(errors).isEmpty(); 101 } 102 103 @Test testFailIfFipsModuleNotAvailable()104 public void testFailIfFipsModuleNotAvailable() throws Exception { 105 Assume.assumeTrue(TinkFips.useOnlyFips()); 106 107 assertThrows(RuntimeException.class, () -> new Ed25519Verify(new byte[32])); 108 } 109 110 /** 111 * Tests that the verifier can verify a the signature for the message and key in the test vector. 112 */ 113 @Test test_validateSignatureInTestVector()114 public void test_validateSignatureInTestVector() throws Exception { 115 Assume.assumeFalse(TinkFips.useOnlyFips()); 116 // We are not using parameterized tests because the next line cannot be run if useOnlyFips. 117 SignatureTestVector[] testVectors = Ed25519TestUtil.createEd25519TestVectors(); 118 for (SignatureTestVector testVector : testVectors) { 119 120 Ed25519PrivateKey key = (Ed25519PrivateKey) testVector.getPrivateKey(); 121 PublicKeyVerify verifier = Ed25519Verify.create(key.getPublicKey()); 122 verifier.verify(testVector.getSignature(), testVector.getMessage()); 123 } 124 } 125 126 @Test test_computeAndValidate_modifiedMessage_throws()127 public void test_computeAndValidate_modifiedMessage_throws() throws Exception { 128 Assume.assumeFalse(TinkFips.useOnlyFips()); 129 // We are not using parameterized tests because the next line cannot be run if useOnlyFips. 130 SignatureTestVector[] testVectors = Ed25519TestUtil.createEd25519TestVectors(); 131 for (SignatureTestVector testVector : testVectors) { 132 Ed25519PrivateKey key = (Ed25519PrivateKey) testVector.getPrivateKey(); 133 byte[] modifiedMessage = Bytes.concat(testVector.getMessage(), new byte[] {1}); 134 PublicKeyVerify verifier = Ed25519Verify.create(key.getPublicKey()); 135 assertThrows( 136 GeneralSecurityException.class, 137 () -> verifier.verify(testVector.getSignature(), modifiedMessage)); 138 } 139 } 140 141 /** Tests that the verification fails if we modify the output prefix. */ 142 @Test test_computeAndValidate_modifiedOutputPrefix_throws()143 public void test_computeAndValidate_modifiedOutputPrefix_throws() throws Exception { 144 Assume.assumeFalse(TinkFips.useOnlyFips()); 145 // We are not using parameterized tests because the next line cannot be run if useOnlyFips. 146 SignatureTestVector[] testVectors = Ed25519TestUtil.createEd25519TestVectors(); 147 for (SignatureTestVector testVector : testVectors) { 148 Ed25519PrivateKey key = (Ed25519PrivateKey) testVector.getPrivateKey(); 149 if (key.getOutputPrefix().size() == 0) { 150 return; 151 } 152 byte[] modifiedSignature = testVector.getSignature(); 153 modifiedSignature[1] ^= 0x01; 154 PublicKeyVerify verifier = Ed25519Verify.create(key.getPublicKey()); 155 assertThrows( 156 GeneralSecurityException.class, 157 () -> 158 verifier.verify( 159 Arrays.copyOf(modifiedSignature, modifiedSignature.length), 160 testVector.getMessage())); 161 } 162 } 163 } 164