1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.internal.net.eap.crypto; 17 18 import static com.android.internal.net.utils.BigIntegerUtils.bigIntegerToUnsignedByteArray; 19 import static com.android.internal.net.utils.BigIntegerUtils.unsignedByteArrayToBigInteger; 20 21 import org.bouncycastle.crypto.digests.SHA1Digest; 22 23 import java.math.BigInteger; 24 import java.nio.ByteBuffer; 25 26 /** 27 * This class implements the Pseudo-Random Number Generator as specified by FIPS 186-2, change 28 * notice 1, as required by EAP-SIM (RFC 4186) and EAP-AKA (RFC 4187). 29 * 30 * <p>Simplifying constraints allow for some parameters to be permanently fixed: The "b" parameter 31 * is specified to always be 160 by RFC 4186. Likewise, the seed must be 20 bytes and therefore can 32 * never exceed 2^b. 33 */ 34 public class Fips186_2Prf { 35 private static final int SEED_LEN_BYTES = 20; 36 private static final int SHA_OUTPUT_LEN_BYTES = 40; 37 38 /** 39 * Gets the next random based on the PRF described in FIPS 186-2, Change Notice 1. 40 * 41 * @param seed the seed value 42 * @param outputLenBytes the output byte count required. Will run multiple iterations as needed. 43 * @return the byte-array random result 44 */ getRandom(byte[] seed, int outputLenBytes)45 public byte[] getRandom(byte[] seed, int outputLenBytes) { 46 if (seed.length != SEED_LEN_BYTES) { 47 throw new IllegalArgumentException("Invalid seed length. Must be 160b (20B)"); 48 } 49 50 BigInteger xkey = unsignedByteArrayToBigInteger(seed); 51 BigInteger exp_b = new BigInteger("2").pow(SEED_LEN_BYTES * 8); 52 53 ByteBuffer buffer = ByteBuffer.allocate(outputLenBytes); 54 55 // RFC 4186, Appendix B, Step 3: 56 // M is the number of generation runs, based on the desired output bytes (rounded up) 57 // EAP SIM/AKA require at least 16 (K_ENCR) + 16 (K_AUTH) + 64 (MSK) + 64 (EMSK) bytes 58 // (total 160 Bytes) 59 int numIterations = (outputLenBytes + SHA_OUTPUT_LEN_BYTES - 1) / SHA_OUTPUT_LEN_BYTES; 60 for (int j = 0; j < numIterations; j++) { 61 for (int i = 0; i < 2; i++) { 62 // RFC 4186, Appendix B, Step 3.1 XSEED_j = 0 63 // (XSEED_j unused, omitted) 64 65 // RFC 4186, Appendix B, Step 3.2a: XVAL = (XKEY + XSEED_j) mod 2^b 66 // (XSEED_j unused, omitted) 67 BigInteger xval = xkey.mod(exp_b); 68 69 // RFC 4186, Appendix B, Step 3.2b: 70 // w_i = G(t, XVAL) 71 byte[] w_i = new byte[SEED_LEN_BYTES]; 72 Sha1_186_2_FunctionG digest = new Sha1_186_2_FunctionG(); 73 digest.update( 74 bigIntegerToUnsignedByteArray(xval, SEED_LEN_BYTES), 0, SEED_LEN_BYTES); 75 digest.doFinal(w_i, 0); 76 77 // RFC 4186, Appendix B, Step 3.2c: 78 // XKEY = (1 + XKEY + w_i) mod 2^b 79 xkey = xkey.add(BigInteger.ONE).add(unsignedByteArrayToBigInteger(w_i)); 80 xkey = xkey.mod(exp_b); 81 82 // RFC 4186, Appendix B, Step 3.3: 83 // x_j = w_0|w_1 84 buffer.put(w_i, 0, Math.min(buffer.remaining(), w_i.length)); 85 } 86 } 87 88 return buffer.array(); 89 } 90 91 /** 92 * This inner class represents the modifications to the SHA1 digest required for FIPS 186-2 PRFs 93 * 94 * <p>FIPS 186-2 requires the use of a hashing function with exactly the same transforms as 95 * SHA1, but with a slightly different padding (all 0s instead of appending additional metadata 96 * for entropy). 97 * 98 * <p>Specifically, this function extends BouncyCastle's SHA1Digest in order to override the 99 * finish method, preventing the additional padding bytes from being appended (leaving them all 100 * 0). 101 */ 102 private static class Sha1_186_2_FunctionG extends SHA1Digest { 103 // IV (t) specified by SHA-1; Use default. 104 105 @Override finish()106 public void finish() { 107 // Don't do any other processing. We only care about the processBlock() functionality. 108 processBlock(); 109 } 110 } 111 } 112