blob: 77561fc30db9aedc1f50f5b07504aa65b4268b88 [file] [log] [blame]
Paul Crowley0d40d6e72018-11-28 12:48:16 -08001/*
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
17package com.android.server.locksettings;
18
19import java.nio.ByteBuffer;
20import java.security.InvalidKeyException;
21import java.security.NoSuchAlgorithmException;
22
23import javax.crypto.Mac;
24import 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 */
36class SP800Derive {
37 private final byte[] mKeyBytes;
38
39 SP800Derive(byte[] keyBytes) {
40 mKeyBytes = keyBytes;
41 }
42
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
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 */
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 */
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}