Skip to content

Commit 80bf857

Browse files
committed
Add HMAC transformer
fixes #11
1 parent 5d3d31d commit 80bf857

File tree

4 files changed

+91
-0
lines changed

4 files changed

+91
-0
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* use EMPTY constant instance for empty byte array to safe memory #16
1111
* add `startsWith()` and `endsWidth()` methods #12
1212
* add cache for calculating the hashCode
13+
* add HMAC byte transformer #11
1314

1415
## v0.6.0
1516

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,14 @@ can be statically imported for a less verbose syntax:
245245
import static at.favre.lib.bytes.BytesTransformers.*;
246246
```
247247

248+
**HMAC** used to calculate [keyed-hash message authentication code](https://en.wikipedia.org/wiki/HMAC):
249+
250+
```java
251+
Bytes.wrap(array).transform(hmacSha256(macKey32Byte));
252+
Bytes.wrap(array).transform(hmacSha1(macKey20Byte));
253+
Bytes.wrap(array).transform(hmac(macKey20Byte,"HmacMd5"));
254+
```
255+
248256
**Checksum** can be calculated or automatically appended:
249257

250258
```java

src/main/java/at/favre/lib/bytes/BytesTransformers.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package at.favre.lib.bytes;
22

3+
import javax.crypto.Mac;
4+
import javax.crypto.spec.SecretKeySpec;
35
import java.io.ByteArrayInputStream;
46
import java.io.ByteArrayOutputStream;
57
import java.io.IOException;
@@ -113,6 +115,37 @@ public static BytesTransformer decompressGzip() {
113115
return new GzipCompressor(false);
114116
}
115117

118+
/**
119+
* Create a {@link BytesTransformer} which returns the HMAC-SHA1 with given key, of the target byte array
120+
*
121+
* @param key to use for HMAC
122+
* @return hmac
123+
*/
124+
public static BytesTransformer hmacSha1(byte[] key) {
125+
return new HmacTransformer(key, HmacTransformer.HMAC_SHA1);
126+
}
127+
128+
/**
129+
* Create a {@link BytesTransformer} which returns the HMAC-SHA256 with given key, of the target byte array
130+
*
131+
* @param key to use for HMAC
132+
* @return hmac
133+
*/
134+
public static BytesTransformer hmacSha256(byte[] key) {
135+
return new HmacTransformer(key, HmacTransformer.HMAC_SHA256);
136+
}
137+
138+
/**
139+
* Create a {@link BytesTransformer} which returns the HMAC with given key, algorithm of the target byte array
140+
*
141+
* @param key to use for HMAC
142+
* @param algorithmName e.g. 'HmacSHA256' - check if the algorithm is supported on your JVM/runtime
143+
* @return hmac (length depends on algorithm)
144+
*/
145+
public static BytesTransformer hmac(byte[] key, String algorithmName) {
146+
return new HmacTransformer(key, algorithmName);
147+
}
148+
116149
/**
117150
* Shuffles the internal byte array
118151
*/
@@ -303,4 +336,36 @@ public boolean supportInPlaceTransformation() {
303336
return false;
304337
}
305338
}
339+
340+
/**
341+
* HMAC transformer
342+
*/
343+
public static final class HmacTransformer implements BytesTransformer {
344+
static final String HMAC_SHA1 = "HmacSHA1";
345+
static final String HMAC_SHA256 = "HmacSHA256";
346+
347+
private final byte[] secretKey;
348+
private final String macAlgorithmName;
349+
350+
public HmacTransformer(byte[] secretKey, String macAlgorithmName) {
351+
this.macAlgorithmName = macAlgorithmName;
352+
this.secretKey = secretKey;
353+
}
354+
355+
@Override
356+
public byte[] transform(byte[] currentArray, boolean inPlace) {
357+
try {
358+
Mac mac = Mac.getInstance(macAlgorithmName);
359+
mac.init(new SecretKeySpec(secretKey, macAlgorithmName));
360+
return mac.doFinal(currentArray);
361+
} catch (Exception e) {
362+
throw new IllegalArgumentException(e);
363+
}
364+
}
365+
366+
@Override
367+
public boolean supportInPlaceTransformation() {
368+
return false;
369+
}
370+
}
306371
}

src/test/java/at/favre/lib/bytes/BytesTransformTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,4 +445,21 @@ public int compare(Byte o1, Byte o2) {
445445
}).supportInPlaceTransformation());
446446
assertTrue(new BytesTransformers.ShuffleTransformer(new SecureRandom()).supportInPlaceTransformation());
447447
}
448+
449+
@Test
450+
public void transformHmac() {
451+
System.out.println(Bytes.parseHex("d8b6239569b184eb7991").transform(new HmacTransformer(Bytes.parseHex("671536819982").array(), "HmacSHA256")).encodeHex());
452+
453+
assertEquals(Bytes.parseHex("d8f0eda7a00192091ad8fefa501753ae"), Bytes.allocate(16).transform(new HmacTransformer(new byte[16], "HmacMd5")));
454+
assertEquals(Bytes.parseHex("c69c13e005ae8ec628ec1869f334ca056bb38958"), Bytes.allocate(16).transform(new HmacTransformer(new byte[20], "HmacSHA1")));
455+
assertEquals(Bytes.parseHex("c69c13e005ae8ec628ec1869f334ca056bb38958"), Bytes.allocate(16).transform(BytesTransformers.hmacSha1(new byte[20])));
456+
assertEquals(Bytes.parseHex("853c7403937d8b6239569b184eb7993fc5f751aefcea28f2c863858e2d29c50b"), Bytes.allocate(16).transform(new HmacTransformer(new byte[32], "HmacSHA256")));
457+
assertEquals(Bytes.parseHex("9aff87db4fd8df58c9081d8386ccc71c9a0f5fe9491235b7bb17e1be20bbe82b"), Bytes.parseHex("d8b6239569b184eb7991").transform(new HmacTransformer(Bytes.parseHex("671536819982").array(), "HmacSHA256")));
458+
assertEquals(Bytes.parseHex("9aff87db4fd8df58c9081d8386ccc71c9a0f5fe9491235b7bb17e1be20bbe82b"), Bytes.parseHex("d8b6239569b184eb7991").transform(BytesTransformers.hmacSha256(Bytes.parseHex("671536819982").array())));
459+
assertEquals(Bytes.parseHex("9aff87db4fd8df58c9081d8386ccc71c9a0f5fe9491235b7bb17e1be20bbe82b"), Bytes.parseHex("d8b6239569b184eb7991").transform(BytesTransformers.hmac(Bytes.parseHex("671536819982").array(), "HmacSHA256")));
460+
461+
//reference test vectors - see https://tools.ietf.org/html/rfc2104
462+
assertEquals(Bytes.parseHex("9294727a3638bb1c13f48ef8158bfc9d"), Bytes.from("Hi There").transform(new HmacTransformer(Bytes.parseHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").array(), "HmacMd5")));
463+
assertEquals(Bytes.parseHex("56be34521d144c88dbb8c733f0e8b3f6"), Bytes.parseHex("DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD").transform(new HmacTransformer(Bytes.parseHex("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").array(), "HmacMd5")));
464+
}
448465
}

0 commit comments

Comments
 (0)