• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 package com.google.crypto.tink.internal;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 import static java.nio.charset.StandardCharsets.US_ASCII;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertThrows;
22 import static org.junit.Assert.assertTrue;
23 
24 import com.google.crypto.tink.InsecureSecretKeyAccess;
25 import com.google.crypto.tink.util.Bytes;
26 import com.google.crypto.tink.util.SecretBytes;
27 import java.io.InputStream;
28 import java.security.GeneralSecurityException;
29 import java.util.stream.IntStream;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 import org.junit.runners.JUnit4;
33 
34 /** Tests for Tink internal Util class. */
35 @RunWith(JUnit4.class)
36 public final class UtilTest {
37 
38   @Test
randKeyId_repeatedCallsShouldOutputDifferentValues()39   public void randKeyId_repeatedCallsShouldOutputDifferentValues() {
40     assertThat(
41             (int) IntStream.range(0, 4).map(unused -> Util.randKeyId()).boxed().distinct().count())
42         .isAtLeast(2);
43   }
44 
45   @Test
randKeyId_repeatedCallsShouldOutputANegativeValue()46   public void randKeyId_repeatedCallsShouldOutputANegativeValue() {
47     assertThat(IntStream.range(0, 100).map(unused -> Util.randKeyId()).min().getAsInt())
48         .isAtMost(0);
49   }
50 
51   @Test
toBytesFromPrintableAscii_works()52   public void toBytesFromPrintableAscii_works() throws Exception {
53     String pureAsciiString =
54         "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
55     Bytes pureAsciiBytes = Bytes.copyFrom(pureAsciiString.getBytes(US_ASCII));
56     assertThat(Util.toBytesFromPrintableAscii(pureAsciiString)).isEqualTo(pureAsciiBytes);
57   }
58 
59   @Test
toBytesFromPrintableAscii_nonAscii_throws()60   public void toBytesFromPrintableAscii_nonAscii_throws() throws Exception {
61     assertThrows(TinkBugException.class, () -> Util.toBytesFromPrintableAscii("\n"));
62     assertThrows(TinkBugException.class, () -> Util.toBytesFromPrintableAscii(" "));
63     assertThrows(TinkBugException.class, () -> Util.toBytesFromPrintableAscii("\0x7f"));
64     assertThrows(TinkBugException.class, () -> Util.toBytesFromPrintableAscii("ö"));
65   }
66 
67   @Test
checkedToBytesFromPrintableAscii_works()68   public void checkedToBytesFromPrintableAscii_works() throws Exception {
69     String pureAsciiString =
70         "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
71     Bytes pureAsciiBytes = Bytes.copyFrom(pureAsciiString.getBytes("ASCII"));
72     assertThat(Util.checkedToBytesFromPrintableAscii(pureAsciiString)).isEqualTo(pureAsciiBytes);
73   }
74 
75   @Test
checkedToBytesFromPrintableAscii_nonAscii_throws()76   public void checkedToBytesFromPrintableAscii_nonAscii_throws() throws Exception {
77     assertThrows(GeneralSecurityException.class, () -> Util.checkedToBytesFromPrintableAscii("\n"));
78     assertThrows(GeneralSecurityException.class, () -> Util.checkedToBytesFromPrintableAscii(" "));
79     assertThrows(
80         GeneralSecurityException.class, () -> Util.checkedToBytesFromPrintableAscii("\0x7f"));
81     assertThrows(GeneralSecurityException.class, () -> Util.checkedToBytesFromPrintableAscii("ö"));
82   }
83 
84   @Test
testGetAndroidApiLevel()85   public void testGetAndroidApiLevel() throws Exception {
86     try {
87       Class<?> buildVersion = Class.forName("android.os.Build$VERSION");
88       int expectedVersion = buildVersion.getDeclaredField("SDK_INT").getInt(null);
89       assertThat(Util.getAndroidApiLevel()).isEqualTo(expectedVersion);
90     } catch (ReflectiveOperationException e) {
91       assertThat(Util.getAndroidApiLevel()).isEqualTo(null);
92     }
93   }
94 
95   @Test
testIsAndroid()96   public void testIsAndroid() throws Exception {
97     try {
98       Class<?> buildVersion = Class.forName("android.os.Build$VERSION");
99       assertThat(Util.isAndroid()).isTrue();
100     } catch (ReflectiveOperationException e) {
101       assertThat(Util.isAndroid()).isFalse();
102     }
103   }
104 
105   @Test
testIsPrefix()106   public void testIsPrefix() throws Exception {
107     assertTrue(Util.isPrefix(new byte[] {1, 2, 3}, new byte[] {1, 2, 3, 4, 5}));
108     assertTrue(Util.isPrefix(new byte[] {}, new byte[] {1, 2, 3, 4, 5}));
109     assertTrue(Util.isPrefix(new byte[] {}, new byte[] {}));
110     assertTrue(Util.isPrefix(new byte[] {5, 7, 9}, new byte[] {5, 7, 9}));
111 
112     assertFalse(Util.isPrefix(new byte[] {5, 7, 9, 10}, new byte[] {5, 7, 9}));
113     assertFalse(Util.isPrefix(new byte[] {5, 7, 10}, new byte[] {5, 7, 9}));
114     assertFalse(Util.isPrefix(new byte[] {1}, new byte[] {}));
115   }
116 
117   @Test
readIntoSecretBytes_works()118   public void readIntoSecretBytes_works() throws Exception {
119     InputStream fragmentedInputStream =
120         new InputStream() {
121           byte nextNumber = 4;
122 
123           @Override
124           public int read() {
125             return 0;
126           }
127 
128           @Override
129           public int read(byte[] b, int off, int len) {
130             b[off] = nextNumber;
131             nextNumber++;
132             return 1;
133           }
134         };
135     SecretBytes result =
136         Util.readIntoSecretBytes(fragmentedInputStream, 4, InsecureSecretKeyAccess.get());
137 
138     assertThat(result.toByteArray(InsecureSecretKeyAccess.get()))
139         .isEqualTo(new byte[] {4, 5, 6, 7});
140 
141     result = Util.readIntoSecretBytes(fragmentedInputStream, 4, InsecureSecretKeyAccess.get());
142     assertThat(result.toByteArray(InsecureSecretKeyAccess.get()))
143         .isEqualTo(new byte[] {8, 9, 10, 11});
144   }
145 
146   @Test
readIntoSecretBytes_throwsOnNotEnoughPseudorandomness()147   public void readIntoSecretBytes_throwsOnNotEnoughPseudorandomness() throws Exception {
148     byte randomness = 4;
149     InputStream shortInputStream =
150         new InputStream() {
151           int numReads = 3;
152 
153           @Override
154           public int read() {
155             return 0;
156           }
157 
158           @Override
159           public int read(byte[] b, int off, int len) {
160             if (numReads == 0) {
161               return -1;
162             }
163             --numReads;
164             b[off] = randomness;
165             return 1;
166           }
167         };
168     assertThrows(
169         GeneralSecurityException.class,
170         () -> Util.readIntoSecretBytes(shortInputStream, 4, InsecureSecretKeyAccess.get()));
171   }
172 }
173