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 17 package com.android.internal.net.crypto; 18 19 import java.nio.ByteBuffer; 20 21 /** 22 * KeyGenerationUtils is a util class that contains utils for key generation needed by IKEv2 and 23 * EAP. 24 */ 25 public class KeyGenerationUtils { 26 /** 27 * Returns the derived pseudorandom number with the specified length by iteratively applying a 28 * PRF. 29 * 30 * <p>prf+(K, S) outputs a pseudorandom stream by using the PRF iteratively. In this way it can 31 * generate long enough keying material containing all the keys. 32 * 33 * @see <a href="https://tools.ietf.org/html/rfc7296#section-2.13">RFC 7296 Internet Key 34 * Exchange Protocol Version 2 (IKEv2) 2.13. Generating Keying Material </a> 35 * @param byteSigner the PRF used to sign the given data using the given key. 36 * @param keyBytes the key to sign data. 37 * @param dataToSign the data to be signed. 38 * @param keyMaterialLen the length of keying materials to be generated. 39 * @return the byte array of keying materials 40 */ prfPlus( ByteSigner byteSigner, byte[] keyBytes, byte[] dataToSign, int keyMaterialLen)41 public static byte[] prfPlus( 42 ByteSigner byteSigner, byte[] keyBytes, byte[] dataToSign, int keyMaterialLen) { 43 ByteBuffer keyMatBuffer = ByteBuffer.allocate(keyMaterialLen); 44 45 byte[] previousMac = new byte[0]; 46 final int padLen = 1; 47 byte padValue = 1; 48 49 while (keyMatBuffer.remaining() > 0) { 50 ByteBuffer dataToSignBuffer = 51 ByteBuffer.allocate(previousMac.length + dataToSign.length + padLen); 52 dataToSignBuffer.put(previousMac).put(dataToSign).put(padValue); 53 54 previousMac = byteSigner.signBytes(keyBytes, dataToSignBuffer.array()); 55 56 keyMatBuffer.put( 57 previousMac, 0, Math.min(previousMac.length, keyMatBuffer.remaining())); 58 59 padValue++; 60 } 61 62 return keyMatBuffer.array(); 63 } 64 65 /** 66 * ByteSigner is an interface to be used for implementing the byte-signing for generating keys 67 * using {@link KeyGenerationUtils#prfPlus(ByteSigner, byte[], byte[], int)}. 68 */ 69 public interface ByteSigner { 70 /** 71 * Signs the given data using the key given. 72 * 73 * <p>Caller is responsible for providing a valid key according to their use cases. 74 * 75 * @param keyBytes the key to sign data. 76 * @param dataToSign the data to be signed. 77 * @return the signed value. 78 */ signBytes(byte[] keyBytes, byte[] dataToSign)79 byte[] signBytes(byte[] keyBytes, byte[] dataToSign); 80 } 81 } 82