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.aead; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static java.nio.charset.StandardCharsets.UTF_8; 21 import static org.junit.Assert.assertTrue; 22 23 import com.google.crypto.tink.Aead; 24 import com.google.crypto.tink.InsecureSecretKeyAccess; 25 import com.google.crypto.tink.Key; 26 import com.google.crypto.tink.KeyTemplate; 27 import com.google.crypto.tink.KeyTemplates; 28 import com.google.crypto.tink.KeysetHandle; 29 import com.google.crypto.tink.Parameters; 30 import com.google.crypto.tink.RegistryConfiguration; 31 import com.google.crypto.tink.aead.XChaCha20Poly1305Parameters.Variant; 32 import com.google.crypto.tink.internal.KeyManagerRegistry; 33 import com.google.crypto.tink.internal.SlowInputStream; 34 import com.google.crypto.tink.subtle.XChaCha20Poly1305; 35 import com.google.crypto.tink.util.SecretBytes; 36 import java.io.ByteArrayInputStream; 37 import org.junit.Before; 38 import org.junit.Test; 39 import org.junit.experimental.theories.DataPoints; 40 import org.junit.experimental.theories.FromDataPoints; 41 import org.junit.experimental.theories.Theories; 42 import org.junit.experimental.theories.Theory; 43 import org.junit.runner.RunWith; 44 45 /** Test for XChaCha20Poly1305KeyManager. */ 46 @RunWith(Theories.class) 47 public class XChaCha20Poly1305KeyManagerTest { 48 @Before register()49 public void register() throws Exception { 50 AeadConfig.register(); 51 } 52 53 @Test testKeyManagerRegistered()54 public void testKeyManagerRegistered() throws Exception { 55 assertThat( 56 KeyManagerRegistry.globalInstance() 57 .getKeyManager( 58 "type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key", Aead.class)) 59 .isNotNull(); 60 } 61 62 @Test testXChaCha20Poly1305Template()63 public void testXChaCha20Poly1305Template() throws Exception { 64 KeyTemplate template = XChaCha20Poly1305KeyManager.xChaCha20Poly1305Template(); 65 assertThat(template.toParameters()) 66 .isEqualTo(XChaCha20Poly1305Parameters.create(XChaCha20Poly1305Parameters.Variant.TINK)); 67 } 68 69 @Test testRawXChaCha20Poly1305Template()70 public void testRawXChaCha20Poly1305Template() throws Exception { 71 KeyTemplate template = XChaCha20Poly1305KeyManager.rawXChaCha20Poly1305Template(); 72 assertThat(template.toParameters()).isEqualTo(XChaCha20Poly1305Parameters.create()); 73 } 74 75 @Test testKeyTemplatesWork()76 public void testKeyTemplatesWork() throws Exception { 77 Parameters p = XChaCha20Poly1305KeyManager.xChaCha20Poly1305Template().toParameters(); 78 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 79 80 p = XChaCha20Poly1305KeyManager.rawXChaCha20Poly1305Template().toParameters(); 81 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 82 } 83 84 @DataPoints("templateNames") 85 public static final String[] KEY_TEMPLATES = 86 new String[] {"XCHACHA20_POLY1305", "XCHACHA20_POLY1305_RAW"}; 87 88 @Theory testTemplates(@romDataPoints"templateNames") String templateName)89 public void testTemplates(@FromDataPoints("templateNames") String templateName) throws Exception { 90 KeysetHandle h = KeysetHandle.generateNew(KeyTemplates.get(templateName)); 91 assertThat(h.size()).isEqualTo(1); 92 assertThat(h.getAt(0).getKey().getParameters()) 93 .isEqualTo(KeyTemplates.get(templateName).toParameters()); 94 } 95 96 @Test testCreateKeyFromRandomness_tinkVariant_works()97 public void testCreateKeyFromRandomness_tinkVariant_works() throws Exception { 98 byte[] keyMaterial = 99 new byte[] { 100 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 101 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 102 }; 103 XChaCha20Poly1305Parameters parameters = 104 XChaCha20Poly1305Parameters.create(XChaCha20Poly1305Parameters.Variant.TINK); 105 com.google.crypto.tink.aead.XChaCha20Poly1305Key key = 106 XChaCha20Poly1305KeyManager.createXChaChaKeyFromRandomness( 107 parameters, new ByteArrayInputStream(keyMaterial), 123, InsecureSecretKeyAccess.get()); 108 byte[] truncatedKeyMaterial = 109 new byte[] { 110 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 111 25, 26, 27, 28, 29, 30, 31 112 }; 113 114 Key expectedKey = 115 com.google.crypto.tink.aead.XChaCha20Poly1305Key.create( 116 XChaCha20Poly1305Parameters.Variant.TINK, 117 SecretBytes.copyFrom(truncatedKeyMaterial, InsecureSecretKeyAccess.get()), 118 123); 119 assertTrue(key.equalsKey(expectedKey)); 120 } 121 122 @Test testCreateKeyFromRandomness_rawVariant_works()123 public void testCreateKeyFromRandomness_rawVariant_works() throws Exception { 124 byte[] keyMaterial = 125 new byte[] { 126 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 127 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 128 }; 129 XChaCha20Poly1305Parameters parameters = 130 XChaCha20Poly1305Parameters.create(XChaCha20Poly1305Parameters.Variant.NO_PREFIX); 131 com.google.crypto.tink.aead.XChaCha20Poly1305Key key = 132 XChaCha20Poly1305KeyManager.createXChaChaKeyFromRandomness( 133 parameters, new ByteArrayInputStream(keyMaterial), null, InsecureSecretKeyAccess.get()); 134 byte[] truncatedKeyMaterial = 135 new byte[] { 136 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 137 25, 26, 27, 28, 29, 30, 31 138 }; 139 140 Key expectedKey = 141 com.google.crypto.tink.aead.XChaCha20Poly1305Key.create( 142 XChaCha20Poly1305Parameters.Variant.NO_PREFIX, 143 SecretBytes.copyFrom(truncatedKeyMaterial, InsecureSecretKeyAccess.get()), 144 null); 145 assertTrue(key.equalsKey(expectedKey)); 146 } 147 148 @Test testCreateKeyFromRandomness_slowInputStream_works()149 public void testCreateKeyFromRandomness_slowInputStream_works() throws Exception { 150 byte[] keyMaterial = 151 new byte[] { 152 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 153 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 154 }; 155 XChaCha20Poly1305Parameters parameters = 156 XChaCha20Poly1305Parameters.create(XChaCha20Poly1305Parameters.Variant.TINK); 157 com.google.crypto.tink.aead.XChaCha20Poly1305Key key = 158 XChaCha20Poly1305KeyManager.createXChaChaKeyFromRandomness( 159 parameters, SlowInputStream.copyFrom(keyMaterial), 1237, InsecureSecretKeyAccess.get()); 160 byte[] truncatedKeyMaterial = 161 new byte[] { 162 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 163 25, 26, 27, 28, 29, 30, 31 164 }; 165 166 Key expectedKey = 167 com.google.crypto.tink.aead.XChaCha20Poly1305Key.create( 168 XChaCha20Poly1305Parameters.Variant.TINK, 169 SecretBytes.copyFrom(truncatedKeyMaterial, InsecureSecretKeyAccess.get()), 170 1237); 171 assertTrue(key.equalsKey(expectedKey)); 172 } 173 174 @Test callingCreateTwiceGivesDifferentKeys()175 public void callingCreateTwiceGivesDifferentKeys() throws Exception { 176 Parameters p = XChaCha20Poly1305KeyManager.xChaCha20Poly1305Template().toParameters(); 177 Key key = KeysetHandle.generateNew(p).getAt(0).getKey(); 178 for (int i = 0; i < 1000; ++i) { 179 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().equalsKey(key)).isFalse(); 180 } 181 } 182 183 @Test getPrimitiveKeysetHandle()184 public void getPrimitiveKeysetHandle() throws Exception { 185 com.google.crypto.tink.aead.XChaCha20Poly1305Key key = 186 com.google.crypto.tink.aead.XChaCha20Poly1305Key.create( 187 Variant.TINK, SecretBytes.randomBytes(32), 42); 188 KeysetHandle keysetHandle = 189 KeysetHandle.newBuilder().addEntry(KeysetHandle.importKey(key).makePrimary()).build(); 190 byte[] plaintext = "plaintext".getBytes(UTF_8); 191 byte[] aad = "aad".getBytes(UTF_8); 192 193 Aead aead = keysetHandle.getPrimitive(RegistryConfiguration.get(), Aead.class); 194 Aead directAead = XChaCha20Poly1305.create(key); 195 196 197 assertThat(aead.decrypt(directAead.encrypt(plaintext, aad), aad)).isEqualTo(plaintext); 198 assertThat(directAead.decrypt(aead.encrypt(plaintext, aad), aad)).isEqualTo(plaintext); 199 } 200 } 201