Overview id-mask bkdf singlestep-kdf bcrypt slf4j-timber armadillo bytes-java hkdf dice under-the-hood uber-apk-signer uber-adb-tools indoor-positioning density-converter Dali BlurTestAndroid
Hashed Message Authentication Code (HMAC)-based key derivation function (HKDF), can be used as a building block in various protocols and applications. The key derivation function (KDF) is intended to support a wide range of applications and requirements, and is conservative in its use of cryptographic hash functions. It is likely to have better security properties than KDF's based on just a hash functions alone. See RFC 5869 for full detail. HKDF specifies a version of the NIST Special Publication 800-56C "Two-Step Key Derivation" scheme.
This is a standalone, lightweight, simple to use, fully tested and stable implementation in Java. The code is compiled with target Java 7 to be compatible with most Android versions as well as normal Java applications. It passes all test vectors from RFC 5869 Appendix A.
Add dependency to your pom.xml
(check latest release):
1<dependency>
2 <groupId>at.favre.lib</groupId>
3 <artifactId>hkdf</artifactId>
4 <version>{latest-version}</version>
5</dependency>
A very simple example:
1byte[] pseudoRandomKey = HKDF.fromHmacSha256().extract(null, lowEntropyInput);
2byte[] outputKeyingMaterial = HKDF.fromHmacSha256().expand(pseudoRandomKey, null, 64);
This example creates a high-quality AES secret key and initialization vector from a shared secret calculated by a key agreement protocol and encrypts with CBC block mode:
1//if no dynamic salt is available, a static salt is better than null
2byte[] staticSalt32Byte = new byte[]{(byte) 0xDA, (byte) 0xAC, 0x3E, 0x10, 0x55, (byte) 0xB5, (byte) 0xF1, 0x3E, 0x53, (byte) 0xE4, 0x70, (byte) 0xA8, 0x77, 0x79, (byte) 0x8E, 0x0A, (byte) 0x89, (byte) 0xAE, (byte) 0x96, 0x5F, 0x19, 0x5D, 0x53, 0x62, 0x58, (byte) 0x84, 0x2C, 0x09, (byte) 0xAD, 0x6E, 0x20, (byte) 0xD4};
3
4//example input
5byte[] sharedSecret = ...;
6
7HKDF hkdf = HKDF.fromHmacSha256();
8
9//extract the "raw" data to create output with concentrated entropy
10byte[] pseudoRandomKey = hkdf.extract(staticSalt32Byte, sharedSecret);
11
12//create expanded bytes for e.g. AES secret key and IV
13byte[] expandedAesKey = hkdf.expand(pseudoRandomKey, "aes-key".getBytes(StandardCharsets.UTF_8), 16);
14byte[] expandedIv = hkdf.expand(pseudoRandomKey, "aes-iv".getBytes(StandardCharsets.UTF_8), 16);
15
16//Example boilerplate encrypting a simple string with created key/iv
17SecretKey key = new SecretKeySpec(expandedAesKey, "AES"); //AES-128 key
18Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
19cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(expandedIv));
20byte[] encrypted = cipher.doFinal("my secret message".getBytes(StandardCharsets.UTF_8));
Note: HKDF is not suited for password-based key derivation, since it has no key stretching property. Use something like PBKDF2 or bcrpyt for that.
1//don't use md5, this is just an example
2HKDF hkdfMd5 = HKDF.from(new HkdfMacFactory.Default("HmacMD5", 16, Security.getProvider("SunJCE")));
3
4byte[] lowEntropyInput = new byte[]{0x62, 0x58, (byte) 0x84, 0x2C};
5byte[] outputKeyingMaterial = hkdfMd5.extractAndExpand(null, lowEntropyInput null, 32);
The artifacts are deployed to jcenter and Maven Central.
Add dependency to your pom.xml
:
1<dependency>
2 <groupId>at.favre.lib</groupId>
3 <artifactId>hkdf</artifactId>
4 <version>{latest-version}</version>
5</dependency>
Add to your build.gradle
module dependencies:
1compile group: 'at.favre.lib', name: 'hkdf', version: '{latest-version}'
For the full description see the RFC 5869. For an in-depth discussion about the security considerations see the Paper "Cryptographic Extraction and Key Derivation: The HKDF Scheme (2010)" by Hugo Krawczyk. The following is a summary of the 2 sources above. If there seems to be a contradiction, the original sources are always correct over this.
HKDF follows the "extract-then-expand" paradigm, where the KDF logically consists of two modules.
Note that some existing KDF specifications, such as NIST Special Publication 800-56A, NIST Special Publication 800-108 and IEEE Standard 1363a-2004, either only consider the second stage (expanding a pseudorandom key), or do not explicitly differentiate between the "extract" and "expand" stages, often resulting in design shortcomings. The goal of this HKDF is to accommodate a wide range of KDF requirements while minimizing the assumptions about the underlying hash function.
HKDF is intended for use in a wide variety of KDF applications. Some applications will not be able to use HKDF "as-is" due to specific operational requirements. One significant example is the derivation of cryptographic keys from a source of low entropy, such as a user's password. In the case of password-based KDFs, a main goal is to slow down dictionary attacks. HKDF naturally accommodates the use of salt; however, a slowing down mechanism is not part of this specification. Therefore, for a user's password, other KDFs might be considered like: PKDF2, bcryt, scrypt or Argon2 which are all designed to be computationally intensive.
The following examples are from RFC5869 Section 4:
The expand phase includes an "info" parameter which should be used to create multiple key material from a single PRK source. For example a Secret Key and IV from a shared Diffie-Hellman Value.
These two functions may also be combined and used to form a PRNG to improve a random number generator's potentially-biased output, as well as protect it from analysis and help defend the random number generation from malicious inputs.
This project uses the OWASP Dependency-Check which is a utility that identifies project dependencies and checks if there are any known, publicly disclosed, vulnerabilities against a NIST database. The build will fail if any issue is found.
The provided JARs in the Github release page are signed with my private key:
1CN=Patrick Favre-Bulle, OU=Private, O=PF Github Open Source, L=Vienna, ST=Vienna, C=AT
2Validity: Thu Sep 07 16:40:57 SGT 2017 to: Fri Feb 10 16:40:57 SGT 2034
3SHA1: 06:DE:F2:C5:F7:BC:0C:11:ED:35:E2:0F:B1:9F:78:99:0F:BE:43:C4
4SHA256: 2B:65:33:B0:1C:0D:2A:69:4E:2D:53:8F:29:D5:6C:D6:87:AF:06:42:1F:1A:EE:B3:3C:E0:6D:0B:65:A1:AA:88
Use the jarsigner tool (found in your $JAVA_HOME/bin
folder) folder to verify.
All tags and commits by me are signed with git with my private key:
1GPG key ID: 4FDF85343912A3AB
2Fingerprint: 2FB392FB05158589B767960C4FDF85343912A3AB
If you want to jar sign you need to provide a file keystore.jks
in the
root folder with the correct credentials set in environment variables (
OPENSOURCE_PROJECTS_KS_PW
and OPENSOURCE_PROJECTS_KEY_PW
); alias is
set as pfopensource
.
If you want to skip jar signing just change the skip configuration in the
pom.xml
jar sign plugin to true:
1true
Use the Maven wrapper to create a jar including all dependencies
1mvnw clean install
This project uses my common-parent
which centralized a lot of
the plugin versions aswell as providing the checkstyle config rules. Specifically they are maintained in checkstyle-config
. Locally the files will be copied after you mvnw install
into your target
folder and is called
target/checkstyle-checker.xml
. So if you use a plugin for your IDE, use this file as your local configuration.
Copyright 2017 Patrick Favre-Bulle
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
1http://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.
StarOverview How to Centralize your Checkstyle Configuration with Maven A Better Way to Protect Your IDs Security Best Practices: Symmetric Encryption with AES in Java and Android: Part 2: AES-CBC + HMAC The Bcrypt Protocol… is kind of a mess The Concise Interface Implementation Pattern Improving ProGuard Name Obfuscation Handling Proguard as Library Developer Managing Logging in a Multi-Module Android App Security Best Practices: Symmetric Encryption with AES in Java and Android
Patrick Favre-Bulle 2020