1 /* 2 * Copyright (C) 2018 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.server.locksettings; 18 19 import java.nio.ByteBuffer; 20 import java.security.InvalidKeyException; 21 import java.security.NoSuchAlgorithmException; 22 23 import javax.crypto.Mac; 24 import javax.crypto.spec.SecretKeySpec; 25 26 /** 27 * Implementation of NIST SP800-108 28 * "Recommendation for Key Derivation Using Pseudorandom Functions" 29 * Hardcoded: 30 * [PRF=HMAC_SHA256] 31 * [CTRLOCATION=BEFORE_FIXED] 32 * [RLEN=32_BITS] 33 * L = 256 34 * L suffix: 32 bits 35 */ 36 class SP800Derive { 37 private final byte[] mKeyBytes; 38 SP800Derive(byte[] keyBytes)39 SP800Derive(byte[] keyBytes) { 40 mKeyBytes = keyBytes; 41 } 42 getMac()43 private Mac getMac() { 44 try { 45 final Mac m = Mac.getInstance("HmacSHA256"); 46 m.init(new SecretKeySpec(mKeyBytes, m.getAlgorithm())); 47 return m; 48 } catch (InvalidKeyException | NoSuchAlgorithmException e) { 49 throw new RuntimeException(e); 50 } 51 } 52 update32(Mac m, int v)53 private static void update32(Mac m, int v) { 54 m.update(ByteBuffer.allocate(Integer.BYTES).putInt(v).array()); 55 } 56 57 /** 58 * Generate output from a single, fixed input. 59 */ fixedInput(byte[] fixedInput)60 public byte[] fixedInput(byte[] fixedInput) { 61 final Mac m = getMac(); 62 update32(m, 1); // Hardwired counter value 63 m.update(fixedInput); 64 return m.doFinal(); 65 } 66 67 /** 68 * Generate output from a label and context. We add a length field at the end of the context to 69 * disambiguate it from the length even in the presence of zero bytes. 70 */ withContext(byte[] label, byte[] context)71 public byte[] withContext(byte[] label, byte[] context) { 72 final Mac m = getMac(); 73 // Hardwired counter value: 1 74 update32(m, 1); // Hardwired counter value 75 m.update(label); 76 m.update((byte) 0); 77 m.update(context); 78 update32(m, context.length * 8); // Disambiguate context 79 update32(m, 256); // Hardwired output length 80 return m.doFinal(); 81 } 82 } 83