summaryrefslogtreecommitdiff
path: root/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java')
-rw-r--r--src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java107
1 files changed, 30 insertions, 77 deletions
diff --git a/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java b/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java
index 876bd93..1e3b196 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.google.security.cryptauth.lib.securemessage;
import com.google.security.annotations.SuppressInsecureCipherModeCheckerReviewed;
@@ -132,6 +132,7 @@ public class CryptoOps {
* A salt value specific to this library, generated as SHA-256("SecureMessage")
*/
private static final byte[] SALT = sha256("SecureMessage");
+ private static final byte[] CONSTANT_01 = { 0x01 }; // For convenience
/**
* Signs {@code data} using the algorithm specified by {@code sigType} with {@code signingKey}.
@@ -411,31 +412,10 @@ public class CryptoOps {
*/
public static byte[] hkdf(SecretKey inputKeyMaterial, byte[] salt, byte[] info)
throws NoSuchAlgorithmException, InvalidKeyException {
- return hkdf(inputKeyMaterial, salt, info, /* length= */ 32);
- }
-
- /**
- * Implements HKDF (RFC 5869) with the SHA-256 hash.
- *
- * <p>Please make sure to select a salt that is fixed and unique for your codebase, and use the
- * {@code info} parameter to specify any additional bits that should influence the derived key.
- *
- * @param inputKeyMaterial master key from which to derive sub-keys
- * @param salt a (public) randomly generated 256-bit input that can be re-used
- * @param info arbitrary information that is bound to the derived key (i.e., used in its creation)
- * @param length length of returned key material
- * @return raw derived key bytes = HKDF-SHA256(inputKeyMaterial, salt, info)
- * @throws InvalidKeyException if the encoded form of {@code inputKeyMaterial} cannot be accessed
- */
- public static byte[] hkdf(SecretKey inputKeyMaterial, byte[] salt, byte[] info, int length)
- throws NoSuchAlgorithmException, InvalidKeyException {
if ((inputKeyMaterial == null) || (salt == null) || (info == null)) {
throw new NullPointerException();
}
- if (length < 0) {
- throw new IllegalArgumentException("Length must be positive");
- }
- return hkdfSha256Expand(hkdfSha256Extract(inputKeyMaterial, salt), info, length);
+ return hkdfSha256Expand(hkdfSha256Extract(inputKeyMaterial, salt), info);
}
/**
@@ -484,12 +464,12 @@ public class CryptoOps {
}
/**
- * The HKDF (RFC 5869) extraction function, using the SHA-256 hash function. This function is used
- * to pre-process the inputKeyMaterial and mix it with the salt, producing output suitable for use
- * with HKDF expansion function (which produces the actual derived key).
+ * The HKDF (RFC 5869) extraction function, using the SHA-256 hash function. This function is
+ * used to pre-process the inputKeyMaterial and mix it with the salt, producing output suitable
+ * for use with HKDF expansion function (which produces the actual derived key).
*
- * @see #hkdfSha256Expand(byte[], byte[], int)
- * @return HMAC-SHA256(salt, inputKeyMaterial) (salt is the "key" for the HMAC)
+ * @see #hkdfSha256Expand(byte[], byte[])
+ * @return HMAC-SHA256(salt, inputKeyMaterial) (salt is the "key" for the HMAC)
* @throws InvalidKeyException if the encoded form of {@code inputKeyMaterial} cannot be accessed
* @throws NoSuchAlgorithmException if the HmacSHA256 or AES algorithms are unavailable
*/
@@ -511,15 +491,15 @@ public class CryptoOps {
}
/**
- * HKDF (RFC 5869) expansion function, using the SHA-256 hash function.
+ * Special case of HKDF (RFC 5869) expansion function, using the SHA-256 hash function and
+ * allowing for a maximum output length of 256 bits.
*
- * @param pseudoRandomKey should be generated by {@link #hkdfSha256Extract(SecretKey, byte[])}
+ * @param pseudoRandomKey should be generated by {@link #hkdfSha256Expand(byte[], byte[])}
* @param info arbitrary information the derived key should be bound to
- * @param length length of the output key material in bytes
* @return raw derived key bytes = HMAC-SHA256(pseudoRandomKey, info | 0x01)
* @throws NoSuchAlgorithmException if the HmacSHA256 or AES algorithms are unavailable
*/
- private static byte[] hkdfSha256Expand(byte[] pseudoRandomKey, byte[] info, int length)
+ private static byte[] hkdfSha256Expand(byte[] pseudoRandomKey, byte[] info)
throws NoSuchAlgorithmException {
Mac macScheme = Mac.getInstance("HmacSHA256");
try {
@@ -527,38 +507,11 @@ public class CryptoOps {
} catch (InvalidKeyException e) {
throw new AssertionError(e); // This should never happen
}
-
- // Number of blocks N = ceil(hash length / output length).
- int blocks = length / 32;
- if (length % 32 > 0) {
- blocks += 1;
- }
-
- // The counter used to generate the blocks according to the RFC is only one byte long,
- // which puts a limit on the number of blocks possible.
- if (blocks > 0xFF) {
- throw new IllegalArgumentException("Maximum HKDF output length exceeded.");
- }
-
- byte[] outputBlock = new byte[32];
- byte[] counter = new byte[1];
- byte[] output = new byte[32 * blocks];
- for (int i = 0; i < blocks; ++i) {
- macScheme.reset();
- if (i > 0) {
- // Previous block
- macScheme.update(outputBlock);
- }
- // Arbitrary info
- macScheme.update(info);
- // Counter
- counter[0] = (byte) (i + 1);
- outputBlock = macScheme.doFinal(counter);
-
- System.arraycopy(outputBlock, 0, output, 32 * i, 32);
- }
-
- return subarray(output, 0, length);
+ // Arbitrary "info" to be included in the MAC.
+ macScheme.update(info);
+ // Note that RFC 5869 computes number of blocks N = ceil(hash length / output length), but
+ // here we only deal with a 256 bit hash up to a 256 bit output, yielding N=1.
+ return macScheme.doFinal(CONSTANT_01);
}
}