xref: /aosp_15_r20/external/tink/java_src/src/main/java/com/google/crypto/tink/internal/Util.java (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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 
17 package com.google.crypto.tink.internal;
18 
19 import com.google.crypto.tink.util.Bytes;
20 import java.nio.charset.Charset;
21 import java.security.GeneralSecurityException;
22 import java.security.SecureRandom;
23 import java.util.Objects;
24 import javax.annotation.Nullable;
25 
26 /** Helper functions used throughout Tink, for Tink internal use only. */
27 public final class Util {
28   /** Android 18-compatible alternative to {@link java.nio.charset.StandardCharsets#UTF_8}. */
29   public static final Charset UTF_8 = Charset.forName("UTF-8");
30 
31   /** Returns a positive random int which can be used as a key ID in a keyset. */
randKeyId()32   public static int randKeyId() {
33     SecureRandom secureRandom = new SecureRandom();
34     byte[] rand = new byte[4];
35     int result = 0;
36     while (result == 0) {
37       secureRandom.nextBytes(rand);
38       // TODO(b/148124847): Other languages create key_ids with the MSB set, so we should here too.
39       result =
40           ((rand[0] & 0x7f) << 24)
41               | ((rand[1] & 0xff) << 16)
42               | ((rand[2] & 0xff) << 8)
43               | (rand[3] & 0xff);
44     }
45     return result;
46   }
47 
toByteFromPrintableAscii(char c)48   private static final byte toByteFromPrintableAscii(char c) {
49     if (c < '!' || c > '~') {
50       throw new TinkBugException("Not a printable ASCII character: " + c);
51     }
52     return (byte) c;
53   }
54 
checkedToByteFromPrintableAscii(char c)55   private static final byte checkedToByteFromPrintableAscii(char c)
56       throws GeneralSecurityException {
57     if (c < '!' || c > '~') {
58       throw new GeneralSecurityException("Not a printable ASCII character: " + c);
59     }
60     return (byte) c;
61   }
62 
63   /**
64    * Converts a string {@code s} to a corresponding {@link Bytes} object.
65    *
66    * <p>The string must contain only printable ASCII characters; calling it in any other way is a
67    * considered a bug in Tink. Spaces are not allowed.
68    *
69    * @throws TinkBugException if s contains a character which is not a printable ASCII character or
70    *     a space.
71    */
toBytesFromPrintableAscii(String s)72   public static final Bytes toBytesFromPrintableAscii(String s) {
73     byte[] result = new byte[s.length()];
74     for (int i = 0; i < s.length(); ++i) {
75       result[i] = toByteFromPrintableAscii(s.charAt(i));
76     }
77     return Bytes.copyFrom(result);
78   }
79 
80   /**
81    * Converts a string {@code s} to a corresponding {@link Bytes} object.
82    *
83    * @throws GeneralSecurityException if s contains a character which is not a printable ASCII
84    *     character or a space.
85    */
checkedToBytesFromPrintableAscii(String s)86   public static final Bytes checkedToBytesFromPrintableAscii(String s)
87       throws GeneralSecurityException {
88     byte[] result = new byte[s.length()];
89     for (int i = 0; i < s.length(); ++i) {
90       result[i] = checkedToByteFromPrintableAscii(s.charAt(i));
91     }
92     return Bytes.copyFrom(result);
93   }
94 
95   /**
96    * Best-effort checks that this is Android.
97    *
98    * <p>Note: this is more tricky than it seems. For example, using reflection to see if
99    * android.os.Build.SDK_INT exists might fail because proguard might break the
100    * reflection part. Using build dispatching can also fail if there are issues in the build graph
101    * (see cl/510374081).
102    *
103    * @return true if running on Android.
104    */
isAndroid()105   public static boolean isAndroid() {
106     // https://developer.android.com/reference/java/lang/System#getProperties%28%29
107     return Objects.equals(System.getProperty("java.vendor"), "The Android Project");
108   }
109 
110   /** Returns the current Android API level as integer or null if we do not run on Android. */
111   @Nullable
getAndroidApiLevel()112   public static Integer getAndroidApiLevel() {
113     if (!isAndroid()) {
114       return null;
115     }
116     return BuildDispatchedCode.getApiLevel();
117   }
118 
Util()119   private Util() {}
120 }
121