· 6 years ago · Jul 03, 2019, 01:24 AM
1package com.nike.snkrs.core.security;
2
3import android.os.Build;
4import android.os.Build.VERSION;
5import android.os.Process;
6import android.support.media.ExifInterface;
7import android.util.Base64;
8import com.facebook.stetho.common.Utf8Charset;
9import defpackage.bmw;
10import java.io.ByteArrayOutputStream;
11import java.io.DataInputStream;
12import java.io.DataOutputStream;
13import java.io.File;
14import java.io.FileInputStream;
15import java.io.FileOutputStream;
16import java.io.IOException;
17import java.io.OutputStream;
18import java.io.UnsupportedEncodingException;
19import java.security.GeneralSecurityException;
20import java.security.InvalidKeyException;
21import java.security.NoSuchAlgorithmException;
22import java.security.Provider;
23import java.security.SecureRandom;
24import java.security.SecureRandomSpi;
25import java.util.Arrays;
26import java.util.concurrent.atomic.AtomicBoolean;
27import javax.crypto.Cipher;
28import javax.crypto.KeyGenerator;
29import javax.crypto.Mac;
30import javax.crypto.SecretKey;
31import javax.crypto.SecretKeyFactory;
32import javax.crypto.spec.IvParameterSpec;
33import javax.crypto.spec.PBEKeySpec;
34import javax.crypto.spec.SecretKeySpec;
35
36public final class AesCbcCryptoWithIntegrity {
37 protected static final int AES_KEY_LENGTH_BITS = 256;
38 protected static final boolean ALLOW_BROKEN_PRNG = false;
39 public static final int BASE64_FLAGS = 2;
40 protected static final String CIPHER = "AES";
41 protected static final String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding";
42 public static final String CRYPTO_SEPARATOR_CHARACTER = ":";
43 protected static final String HMAC_ALGORITHM = "HmacSHA256";
44 protected static final int HMAC_KEY_LENGTH_BITS = 256;
45 protected static final int IV_LENGTH_BYTES = 16;
46 protected static final String PBE_ALGORITHM = "PBKDF2WithHmacSHA1";
47 protected static final int PBE_ITERATION_COUNT = 10000;
48 protected static final int PBE_SALT_LENGTH_BITS = 256;
49 protected static final String RANDOM_ALGORITHM = "SHA1PRNG";
50 protected static final String TOTALLY_NOT_THE_AES_HMAC_COMBINED_KEY = "PwH3TvthqnjX0FzDxKa+SZMRU/S2UTN93np8ElkaRPk=:sK7ED/JKoZykinRaM4O4molmFWi+quTs82Hgt9eOcYY=";
51 protected static final AtomicBoolean sPrngFixed = new AtomicBoolean(false);
52
53 public static class CipherTextIvMac {
54 private final byte[] cipherText;
55 private final byte[] iv;
56 private final byte[] mac;
57
58 public CipherTextIvMac(byte[] bArr, byte[] bArr2, byte[] bArr3) {
59 this.cipherText = new byte[bArr.length];
60 System.arraycopy(bArr, 0, this.cipherText, 0, bArr.length);
61 this.iv = new byte[bArr2.length];
62 System.arraycopy(bArr2, 0, this.iv, 0, bArr2.length);
63 this.mac = new byte[bArr3.length];
64 System.arraycopy(bArr3, 0, this.mac, 0, bArr3.length);
65 }
66
67 public CipherTextIvMac(String str) {
68 String[] split = str.split(AesCbcCryptoWithIntegrity.CRYPTO_SEPARATOR_CHARACTER);
69 if (split.length == 3) {
70 this.iv = Base64.decode(split[0], 2);
71 this.mac = Base64.decode(split[1], 2);
72 this.cipherText = Base64.decode(split[2], 2);
73 return;
74 }
75 StringBuilder stringBuilder = new StringBuilder();
76 stringBuilder.append("Cannot parse iv:ciphertext:mac! base64IvAndCiphertext was: ");
77 stringBuilder.append(str);
78 throw new IllegalArgumentException(stringBuilder.toString());
79 }
80
81 public static byte[] ivCipherConcat(byte[] bArr, byte[] bArr2) {
82 byte[] bArr3 = new byte[(bArr.length + bArr2.length)];
83 System.arraycopy(bArr, 0, bArr3, 0, bArr.length);
84 System.arraycopy(bArr2, 0, bArr3, bArr.length, bArr2.length);
85 return bArr3;
86 }
87
88 public byte[] getCipherText() {
89 return this.cipherText;
90 }
91
92 public byte[] getIv() {
93 return this.iv;
94 }
95
96 public byte[] getMac() {
97 return this.mac;
98 }
99
100 public String toString() {
101 String encodeToString = Base64.encodeToString(this.iv, 2);
102 String encodeToString2 = Base64.encodeToString(this.cipherText, 2);
103 String encodeToString3 = Base64.encodeToString(this.mac, 2);
104 StringBuilder stringBuilder = new StringBuilder();
105 stringBuilder.append(encodeToString);
106 stringBuilder.append(AesCbcCryptoWithIntegrity.CRYPTO_SEPARATOR_CHARACTER);
107 stringBuilder.append(encodeToString3);
108 stringBuilder.append(AesCbcCryptoWithIntegrity.CRYPTO_SEPARATOR_CHARACTER);
109 stringBuilder.append(encodeToString2);
110 return stringBuilder.toString();
111 }
112
113 public int hashCode() {
114 return ((((Arrays.hashCode(this.cipherText) + 31) * 31) + Arrays.hashCode(this.iv)) * 31) + Arrays.hashCode(this.mac);
115 }
116
117 public boolean equals(Object obj) {
118 boolean z = true;
119 if (this == obj) {
120 return true;
121 }
122 if (obj == null || getClass() != obj.getClass()) {
123 return false;
124 }
125 CipherTextIvMac cipherTextIvMac = (CipherTextIvMac) obj;
126 if (!(Arrays.equals(this.cipherText, cipherTextIvMac.cipherText) && Arrays.equals(this.iv, cipherTextIvMac.iv) && Arrays.equals(this.mac, cipherTextIvMac.mac))) {
127 z = false;
128 }
129 return z;
130 }
131 }
132
133 public static final class PrngFixes {
134 private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL = getBuildFingerprintAndDeviceSerial();
135 private static final int VERSION_CODE_JELLY_BEAN = 16;
136 private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18;
137
138 public static class LinuxPRNGSecureRandom extends SecureRandomSpi {
139 private static final File URANDOM_FILE = new File("/dev/urandom");
140 private static final Object sLock = new Object();
141 private static DataInputStream sUrandomIn;
142 private static OutputStream sUrandomOut;
143 private boolean mSeeded;
144
145 /* Access modifiers changed, original: protected */
146 /* JADX WARNING: Missing exception handler attribute for start block: B:15:0x0015 */
147 public void engineSetSeed(byte[] r5) {
148 /*
149 r4 = this;
150 r0 = 1;
151 r1 = sLock; Catch:{ IOException -> 0x0015 }
152 monitor-enter(r1); Catch:{ IOException -> 0x0015 }
153 r2 = r4.getUrandomOutputStream(); Catch:{ all -> 0x0010 }
154 monitor-exit(r1); Catch:{ all -> 0x0010 }
155 r2.write(r5); Catch:{ IOException -> 0x0015 }
156 r2.flush(); Catch:{ IOException -> 0x0015 }
157 goto L_0x0021;
158 L_0x0010:
159 r5 = move-exception;
160 monitor-exit(r1); Catch:{ all -> 0x0010 }
161 throw r5; Catch:{ IOException -> 0x0015 }
162 L_0x0013:
163 r5 = move-exception;
164 goto L_0x0024;
165 L_0x0015:
166 r5 = "Failed to mix seed into %s";
167 r1 = new java.lang.Object[r0]; Catch:{ all -> 0x0013 }
168 r2 = 0;
169 r3 = URANDOM_FILE; Catch:{ all -> 0x0013 }
170 r1[r2] = r3; Catch:{ all -> 0x0013 }
171 defpackage.bmw.w(r5, r1); Catch:{ all -> 0x0013 }
172 L_0x0021:
173 r4.mSeeded = r0;
174 return;
175 L_0x0024:
176 r4.mSeeded = r0;
177 throw r5;
178 */
179 throw new UnsupportedOperationException("Method not decompiled: com.nike.snkrs.core.security.AesCbcCryptoWithIntegrity$PrngFixes$LinuxPRNGSecureRandom.engineSetSeed(byte[]):void");
180 }
181
182 /* Access modifiers changed, original: protected */
183 public void engineNextBytes(byte[] bArr) {
184 if (!this.mSeeded) {
185 engineSetSeed(PrngFixes.generateSeed());
186 }
187 try {
188 DataInputStream urandomInputStream;
189 synchronized (sLock) {
190 urandomInputStream = getUrandomInputStream();
191 }
192 synchronized (urandomInputStream) {
193 urandomInputStream.readFully(bArr);
194 }
195 } catch (IOException e) {
196 StringBuilder stringBuilder = new StringBuilder();
197 stringBuilder.append("Failed to read from ");
198 stringBuilder.append(URANDOM_FILE);
199 throw new SecurityException(stringBuilder.toString(), e);
200 }
201 }
202
203 /* Access modifiers changed, original: protected */
204 public byte[] engineGenerateSeed(int i) {
205 byte[] bArr = new byte[i];
206 engineNextBytes(bArr);
207 return bArr;
208 }
209
210 private DataInputStream getUrandomInputStream() {
211 DataInputStream dataInputStream;
212 synchronized (sLock) {
213 if (sUrandomIn == null) {
214 try {
215 sUrandomIn = new DataInputStream(new FileInputStream(URANDOM_FILE));
216 } catch (IOException e) {
217 StringBuilder stringBuilder = new StringBuilder();
218 stringBuilder.append("Failed to open ");
219 stringBuilder.append(URANDOM_FILE);
220 stringBuilder.append(" for reading");
221 throw new SecurityException(stringBuilder.toString(), e);
222 }
223 }
224 dataInputStream = sUrandomIn;
225 }
226 return dataInputStream;
227 }
228
229 private OutputStream getUrandomOutputStream() throws IOException {
230 OutputStream outputStream;
231 synchronized (sLock) {
232 if (sUrandomOut == null) {
233 sUrandomOut = new FileOutputStream(URANDOM_FILE);
234 }
235 outputStream = sUrandomOut;
236 }
237 return outputStream;
238 }
239 }
240
241 private static class LinuxPRNGSecureRandomProvider extends Provider {
242 public LinuxPRNGSecureRandomProvider() {
243 super("LinuxPRNG", 1.0d, "A Linux-specific random number provider that uses /dev/urandom");
244 put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName());
245 put("SecureRandom.SHA1PRNG ImplementedIn", ExifInterface.TAG_SOFTWARE);
246 }
247 }
248
249 private PrngFixes() {
250 }
251
252 public static void apply() {
253 applyOpenSSLFix();
254 installLinuxPRNGSecureRandom();
255 }
256
257 private static void applyOpenSSLFix() throws SecurityException {
258 if (VERSION.SDK_INT >= 16 && VERSION.SDK_INT <= 18) {
259 try {
260 Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto").getMethod("RAND_seed", new Class[]{byte[].class}).invoke(null, new Object[]{generateSeed()});
261 int intValue = ((Integer) Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto").getMethod("RAND_load_file", new Class[]{String.class, Long.TYPE}).invoke(null, new Object[]{"/dev/urandom", Integer.valueOf(1024)})).intValue();
262 if (intValue != 1024) {
263 StringBuilder stringBuilder = new StringBuilder();
264 stringBuilder.append("Unexpected number of bytes read from Linux PRNG: ");
265 stringBuilder.append(intValue);
266 throw new IOException(stringBuilder.toString());
267 }
268 } catch (Exception e) {
269 throw new SecurityException("Failed to seed OpenSSL PRNG", e);
270 }
271 }
272 }
273
274 /* JADX WARNING: Removed duplicated region for block: B:33:0x00a5 A:{Catch:{ NoSuchAlgorithmException -> 0x009c, all -> 0x002e }} */
275 /* JADX WARNING: Removed duplicated region for block: B:18:0x0056 A:{SYNTHETIC, Splitter:B:18:0x0056} */
276 private static void installLinuxPRNGSecureRandom() throws java.lang.SecurityException {
277 /*
278 r0 = android.os.Build.VERSION.SDK_INT;
279 r1 = 18;
280 if (r0 <= r1) goto L_0x0007;
281 L_0x0006:
282 return;
283 L_0x0007:
284 r0 = "SecureRandom.SHA1PRNG";
285 r0 = java.security.Security.getProviders(r0);
286 r1 = java.security.Security.class;
287 monitor-enter(r1);
288 r2 = 1;
289 if (r0 == 0) goto L_0x0031;
290 L_0x0013:
291 r3 = r0.length; Catch:{ all -> 0x002e }
292 if (r3 < r2) goto L_0x0031;
293 L_0x0016:
294 r3 = 0;
295 r0 = r0[r3]; Catch:{ all -> 0x002e }
296 r0 = r0.getClass(); Catch:{ all -> 0x002e }
297 r0 = r0.getSimpleName(); Catch:{ all -> 0x002e }
298 r3 = com.nike.snkrs.core.security.AesCbcCryptoWithIntegrity.PrngFixes.LinuxPRNGSecureRandomProvider.class;
299 r3 = r3.getSimpleName(); Catch:{ all -> 0x002e }
300 r0 = r0.equals(r3); Catch:{ all -> 0x002e }
301 if (r0 != 0) goto L_0x0039;
302 L_0x002d:
303 goto L_0x0031;
304 L_0x002e:
305 r0 = move-exception;
306 goto L_0x00c4;
307 L_0x0031:
308 r0 = new com.nike.snkrs.core.security.AesCbcCryptoWithIntegrity$PrngFixes$LinuxPRNGSecureRandomProvider; Catch:{ all -> 0x002e }
309 r0.<init>(); Catch:{ all -> 0x002e }
310 java.security.Security.insertProviderAt(r0, r2); Catch:{ all -> 0x002e }
311 L_0x0039:
312 r0 = new java.security.SecureRandom; Catch:{ all -> 0x002e }
313 r0.<init>(); Catch:{ all -> 0x002e }
314 r2 = r0.getProvider(); Catch:{ all -> 0x002e }
315 r2 = r2.getClass(); Catch:{ all -> 0x002e }
316 r2 = r2.getSimpleName(); Catch:{ all -> 0x002e }
317 r3 = com.nike.snkrs.core.security.AesCbcCryptoWithIntegrity.PrngFixes.LinuxPRNGSecureRandomProvider.class;
318 r3 = r3.getSimpleName(); Catch:{ all -> 0x002e }
319 r2 = r2.equals(r3); Catch:{ all -> 0x002e }
320 if (r2 == 0) goto L_0x00a5;
321 L_0x0056:
322 r0 = "SHA1PRNG";
323 r0 = java.security.SecureRandom.getInstance(r0); Catch:{ NoSuchAlgorithmException -> 0x009c }
324 r2 = r0.getProvider(); Catch:{ all -> 0x002e }
325 if (r2 == 0) goto L_0x009a;
326 L_0x0062:
327 r2 = r0.getProvider(); Catch:{ all -> 0x002e }
328 r2 = r2.getClass(); Catch:{ all -> 0x002e }
329 r2 = r2.getSimpleName(); Catch:{ all -> 0x002e }
330 r3 = com.nike.snkrs.core.security.AesCbcCryptoWithIntegrity.PrngFixes.LinuxPRNGSecureRandomProvider.class;
331 r3 = r3.getSimpleName(); Catch:{ all -> 0x002e }
332 r2 = r2.equals(r3); Catch:{ all -> 0x002e }
333 if (r2 == 0) goto L_0x007b;
334 L_0x007a:
335 goto L_0x009a;
336 L_0x007b:
337 r2 = new java.lang.SecurityException; Catch:{ all -> 0x002e }
338 r3 = new java.lang.StringBuilder; Catch:{ all -> 0x002e }
339 r3.<init>(); Catch:{ all -> 0x002e }
340 r4 = "SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong Provider: ";
341 r3.append(r4); Catch:{ all -> 0x002e }
342 r0 = r0.getProvider(); Catch:{ all -> 0x002e }
343 r0 = r0.getClass(); Catch:{ all -> 0x002e }
344 r3.append(r0); Catch:{ all -> 0x002e }
345 r0 = r3.toString(); Catch:{ all -> 0x002e }
346 r2.<init>(r0); Catch:{ all -> 0x002e }
347 throw r2; Catch:{ all -> 0x002e }
348 L_0x009a:
349 monitor-exit(r1); Catch:{ all -> 0x002e }
350 return;
351 L_0x009c:
352 r0 = move-exception;
353 r2 = new java.lang.SecurityException; Catch:{ all -> 0x002e }
354 r3 = "SHA1PRNG not available";
355 r2.<init>(r3, r0); Catch:{ all -> 0x002e }
356 throw r2; Catch:{ all -> 0x002e }
357 L_0x00a5:
358 r2 = new java.lang.SecurityException; Catch:{ all -> 0x002e }
359 r3 = new java.lang.StringBuilder; Catch:{ all -> 0x002e }
360 r3.<init>(); Catch:{ all -> 0x002e }
361 r4 = "new SecureRandom() backed by wrong Provider: ";
362 r3.append(r4); Catch:{ all -> 0x002e }
363 r0 = r0.getProvider(); Catch:{ all -> 0x002e }
364 r0 = r0.getClass(); Catch:{ all -> 0x002e }
365 r3.append(r0); Catch:{ all -> 0x002e }
366 r0 = r3.toString(); Catch:{ all -> 0x002e }
367 r2.<init>(r0); Catch:{ all -> 0x002e }
368 throw r2; Catch:{ all -> 0x002e }
369 L_0x00c4:
370 monitor-exit(r1); Catch:{ all -> 0x002e }
371 throw r0;
372 */
373 throw new UnsupportedOperationException("Method not decompiled: com.nike.snkrs.core.security.AesCbcCryptoWithIntegrity$PrngFixes.installLinuxPRNGSecureRandom():void");
374 }
375
376 private static byte[] generateSeed() {
377 try {
378 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
379 DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
380 dataOutputStream.writeLong(System.currentTimeMillis());
381 dataOutputStream.writeLong(System.nanoTime());
382 dataOutputStream.writeInt(Process.myPid());
383 dataOutputStream.writeInt(Process.myUid());
384 dataOutputStream.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL);
385 dataOutputStream.close();
386 return byteArrayOutputStream.toByteArray();
387 } catch (IOException e) {
388 throw new SecurityException("Failed to generate seed", e);
389 }
390 }
391
392 private static String getDeviceSerialNumber() {
393 try {
394 return (String) Build.class.getField("SERIAL").get(null);
395 } catch (Exception unused) {
396 return null;
397 }
398 }
399
400 private static byte[] getBuildFingerprintAndDeviceSerial() {
401 StringBuilder stringBuilder = new StringBuilder();
402 String str = Build.FINGERPRINT;
403 if (str != null) {
404 stringBuilder.append(str);
405 }
406 str = getDeviceSerialNumber();
407 if (str != null) {
408 stringBuilder.append(str);
409 }
410 try {
411 return stringBuilder.toString().getBytes(Utf8Charset.NAME);
412 } catch (UnsupportedEncodingException unused) {
413 throw new RuntimeException("UTF-8 encoding not supported");
414 }
415 }
416 }
417
418 public static class SecretKeys {
419 private SecretKey confidentialityKey;
420 private SecretKey integrityKey;
421
422 public SecretKeys(SecretKey secretKey, SecretKey secretKey2) {
423 setConfidentialityKey(secretKey);
424 setIntegrityKey(secretKey2);
425 }
426
427 public SecretKey getConfidentialityKey() {
428 return this.confidentialityKey;
429 }
430
431 public void setConfidentialityKey(SecretKey secretKey) {
432 this.confidentialityKey = secretKey;
433 }
434
435 public SecretKey getIntegrityKey() {
436 return this.integrityKey;
437 }
438
439 public void setIntegrityKey(SecretKey secretKey) {
440 this.integrityKey = secretKey;
441 }
442
443 public String toString() {
444 StringBuilder stringBuilder = new StringBuilder();
445 stringBuilder.append(Base64.encodeToString(getConfidentialityKey().getEncoded(), 2));
446 stringBuilder.append(AesCbcCryptoWithIntegrity.CRYPTO_SEPARATOR_CHARACTER);
447 stringBuilder.append(Base64.encodeToString(getIntegrityKey().getEncoded(), 2));
448 return stringBuilder.toString();
449 }
450
451 public int hashCode() {
452 return ((this.confidentialityKey.hashCode() + 31) * 31) + this.integrityKey.hashCode();
453 }
454
455 public boolean equals(Object obj) {
456 boolean z = true;
457 if (this == obj) {
458 return true;
459 }
460 if (obj == null || getClass() != obj.getClass()) {
461 return false;
462 }
463 SecretKeys secretKeys = (SecretKeys) obj;
464 if (!(this.integrityKey.equals(secretKeys.integrityKey) && this.confidentialityKey.equals(secretKeys.confidentialityKey))) {
465 z = false;
466 }
467 return z;
468 }
469 }
470
471 protected AesCbcCryptoWithIntegrity() {
472 }
473
474 public static String keyString(SecretKeys secretKeys) {
475 return secretKeys.toString();
476 }
477
478 public static SecretKeys keys(String str) throws InvalidKeyException {
479 String[] split = str.split(CRYPTO_SEPARATOR_CHARACTER);
480 if (split.length == 2) {
481 byte[] decode = Base64.decode(split[0], 2);
482 if (decode.length == 32) {
483 byte[] decode2 = Base64.decode(split[1], 2);
484 if (decode2.length == 32) {
485 return new SecretKeys(new SecretKeySpec(decode, 0, decode.length, CIPHER), new SecretKeySpec(decode2, HMAC_ALGORITHM));
486 }
487 throw new InvalidKeyException("Base64 decoded key is not 256 bytes");
488 }
489 throw new InvalidKeyException("Base64 decoded key is not 256 bytes");
490 }
491 throw new IllegalArgumentException("Cannot parse aesKey:hmacKey");
492 }
493
494 public static SecretKeys generateKey() throws GeneralSecurityException {
495 fixPrng();
496 KeyGenerator instance = KeyGenerator.getInstance(CIPHER);
497 instance.init(256);
498 return new SecretKeys(instance.generateKey(), new SecretKeySpec(randomBytes(32), HMAC_ALGORITHM));
499 }
500
501 public static SecretKeys generateKeyFromPassword(String str, byte[] bArr) throws GeneralSecurityException {
502 fixPrng();
503 byte[] encoded = SecretKeyFactory.getInstance(PBE_ALGORITHM).generateSecret(new PBEKeySpec(str.toCharArray(), bArr, PBE_ITERATION_COUNT, 512)).getEncoded();
504 return new SecretKeys(new SecretKeySpec(copyOfRange(encoded, 0, 32), CIPHER), new SecretKeySpec(copyOfRange(encoded, 32, 64), HMAC_ALGORITHM));
505 }
506
507 public static SecretKeys generateKeyFromPassword(String str, String str2) throws GeneralSecurityException {
508 return generateKeyFromPassword(str, Base64.decode(str2, 2));
509 }
510
511 public static byte[] generateSalt() throws GeneralSecurityException {
512 return randomBytes(256);
513 }
514
515 public static String saltString(byte[] bArr) {
516 return Base64.encodeToString(bArr, 2);
517 }
518
519 public static byte[] generateIv() throws GeneralSecurityException {
520 return randomBytes(16);
521 }
522
523 public static byte[] randomBytes(int i) throws GeneralSecurityException {
524 fixPrng();
525 byte[] bArr = new byte[i];
526 SecureRandom.getInstance(RANDOM_ALGORITHM).nextBytes(bArr);
527 return bArr;
528 }
529
530 public static CipherTextIvMac encrypt(String str) {
531 try {
532 return encrypt(str, keys(TOTALLY_NOT_THE_AES_HMAC_COMBINED_KEY));
533 } catch (UnsupportedEncodingException | GeneralSecurityException e) {
534 bmw.e(e, "Problem encrypting string %s - Error was: %s", str, e.getMessage());
535 return null;
536 }
537 }
538
539 public static CipherTextIvMac encrypt(String str, SecretKeys secretKeys) throws UnsupportedEncodingException, GeneralSecurityException {
540 return encrypt(str, secretKeys, Utf8Charset.NAME);
541 }
542
543 public static CipherTextIvMac encrypt(String str, SecretKeys secretKeys, String str2) throws UnsupportedEncodingException, GeneralSecurityException {
544 return encrypt(str.getBytes(str2), secretKeys);
545 }
546
547 public static CipherTextIvMac encrypt(byte[] bArr, SecretKeys secretKeys) throws GeneralSecurityException {
548 byte[] generateIv = generateIv();
549 Cipher instance = Cipher.getInstance(CIPHER_TRANSFORMATION);
550 instance.init(1, secretKeys.getConfidentialityKey(), new IvParameterSpec(generateIv));
551 generateIv = instance.getIV();
552 bArr = instance.doFinal(bArr);
553 return new CipherTextIvMac(bArr, generateIv, generateMac(CipherTextIvMac.ivCipherConcat(generateIv, bArr), secretKeys.getIntegrityKey()));
554 }
555
556 private static void fixPrng() {
557 if (!sPrngFixed.get()) {
558 synchronized (PrngFixes.class) {
559 if (!sPrngFixed.get()) {
560 PrngFixes.apply();
561 sPrngFixed.set(true);
562 }
563 }
564 }
565 }
566
567 public static String decryptString(String str, boolean z) {
568 try {
569 return decryptString(new CipherTextIvMac(str), keys(TOTALLY_NOT_THE_AES_HMAC_COMBINED_KEY));
570 } catch (UnsupportedEncodingException | GeneralSecurityException e) {
571 bmw.e(e, "Problem decrypting string %s - Error was: %s", str, e.getMessage());
572 return null;
573 }
574 }
575
576 public static String decryptString(CipherTextIvMac cipherTextIvMac, SecretKeys secretKeys, String str) throws UnsupportedEncodingException, GeneralSecurityException {
577 return new String(decrypt(cipherTextIvMac, secretKeys), str);
578 }
579
580 public static String decryptString(CipherTextIvMac cipherTextIvMac, SecretKeys secretKeys) throws UnsupportedEncodingException, GeneralSecurityException {
581 return decryptString(cipherTextIvMac, secretKeys, Utf8Charset.NAME);
582 }
583
584 public static byte[] decrypt(CipherTextIvMac cipherTextIvMac, SecretKeys secretKeys) throws GeneralSecurityException {
585 if (constantTimeEq(generateMac(CipherTextIvMac.ivCipherConcat(cipherTextIvMac.getIv(), cipherTextIvMac.getCipherText()), secretKeys.getIntegrityKey()), cipherTextIvMac.getMac())) {
586 Cipher instance = Cipher.getInstance(CIPHER_TRANSFORMATION);
587 instance.init(2, secretKeys.getConfidentialityKey(), new IvParameterSpec(cipherTextIvMac.getIv()));
588 return instance.doFinal(cipherTextIvMac.getCipherText());
589 }
590 throw new GeneralSecurityException("MAC stored in civ does not match computed MAC.");
591 }
592
593 public static byte[] generateMac(byte[] bArr, SecretKey secretKey) throws NoSuchAlgorithmException, InvalidKeyException {
594 Mac instance = Mac.getInstance(HMAC_ALGORITHM);
595 instance.init(secretKey);
596 return instance.doFinal(bArr);
597 }
598
599 public static boolean constantTimeEq(byte[] bArr, byte[] bArr2) {
600 boolean z = false;
601 if (bArr.length != bArr2.length) {
602 return false;
603 }
604 int i = 0;
605 for (int i2 = 0; i2 < bArr.length; i2++) {
606 i |= bArr[i2] ^ bArr2[i2];
607 }
608 if (i == 0) {
609 z = true;
610 }
611 return z;
612 }
613
614 private static byte[] copyOfRange(byte[] bArr, int i, int i2) {
615 i2 -= i;
616 byte[] bArr2 = new byte[i2];
617 System.arraycopy(bArr, i, bArr2, 0, i2);
618 return bArr2;
619 }
620}