Browse Source

Support SHA256/512 as well

master
Chris Smith 5 years ago
parent
commit
87fcaf252e

+ 17
- 0
app/src/main/java/com/chameth/yaotp/algos/Hmac.kt View File

@@ -0,0 +1,17 @@
1
+package com.chameth.yaotp.algos
2
+
3
+import javax.crypto.Mac
4
+import javax.crypto.spec.SecretKeySpec
5
+
6
+typealias HmacFunc = (ByteArray, ByteArray) -> ByteArray
7
+
8
+fun hmacSha1(keyMaterial: ByteArray, input: ByteArray) = hmac(keyMaterial, input, "HmacSHA1")
9
+fun hmacSha256(keyMaterial: ByteArray, input: ByteArray) = hmac(keyMaterial, input, "HmacSHA256")
10
+fun hmacSha512(keyMaterial: ByteArray, input: ByteArray) = hmac(keyMaterial, input, "HmacSHA512")
11
+
12
+private fun hmac(keyMaterial: ByteArray, input: ByteArray, algorithm: String): ByteArray {
13
+    return with(Mac.getInstance(algorithm)) {
14
+        init(SecretKeySpec(keyMaterial, algorithm))
15
+        doFinal(input)
16
+    }
17
+}

+ 2
- 2
app/src/main/java/com/chameth/yaotp/algos/Hotp.kt View File

@@ -4,9 +4,9 @@ import java.nio.ByteBuffer
4 4
 import kotlin.experimental.and
5 5
 import kotlin.math.pow
6 6
 
7
-fun hotp(key: ByteArray, counter: ByteArray, length: Int = 6) = hmacToHotp(hmacSha1(key, counter), length)
7
+fun hotp(key: ByteArray, counter: ByteArray, length: Int = 6, hmacFunc: HmacFunc = ::hmacSha1) = hmacToHotp(hmacFunc(key, counter), length)
8 8
 
9
-internal fun offsetValue(bytes: ByteArray) = (bytes[19] and 0x0F).toInt()
9
+internal fun offsetValue(bytes: ByteArray) = (bytes[bytes.size - 1] and 0x0F).toInt()
10 10
 
11 11
 internal fun offset(bytes: ByteArray) = offsetValue(bytes).let { bytes.sliceArray(IntRange(it, it + 3)) }
12 12
 

+ 2
- 1
app/src/main/java/com/chameth/yaotp/algos/Totp.kt View File

@@ -2,7 +2,8 @@ package com.chameth.yaotp.algos
2 2
 
3 3
 import java.nio.ByteBuffer
4 4
 
5
-fun totp(key: ByteArray, startTime: Long = 0, step: Int = 30, currentTime: Long = currentTime(), length: Int = 6) = hotp(key, count(startTime, step, currentTime).toByteArray(), length)
5
+fun totp(key: ByteArray, startTime: Long = 0, step: Int = 30, currentTime: Long = currentTime(), length: Int = 6, hmacFunc: HmacFunc = ::hmacSha1)
6
+        = hotp(key, count(startTime, step, currentTime).toByteArray(), length, hmacFunc)
6 7
 
7 8
 internal fun count(startTime: Long, step: Int, currentTime: Long) = (currentTime - startTime) / step
8 9
 

+ 0
- 15
app/src/main/java/com/chameth/yaotp/algos/Utils.kt View File

@@ -1,15 +0,0 @@
1
-package com.chameth.yaotp.algos
2
-
3
-import javax.crypto.Mac
4
-import javax.crypto.spec.SecretKeySpec
5
-
6
-private const val HMAC_SHA1_ALGORITHM = "HmacSHA1"
7
-
8
-fun hmacSha1(keyMaterial: ByteArray, input: ByteArray): ByteArray {
9
-    return with(Mac.getInstance(HMAC_SHA1_ALGORITHM)) {
10
-        init(getKey(keyMaterial))
11
-        doFinal(input)
12
-    }
13
-}
14
-
15
-private fun getKey(material: ByteArray) = SecretKeySpec(material, HMAC_SHA1_ALGORITHM)

+ 36
- 0
app/src/test/java/com/chameth/yaotp/algos/HmacTest.kt View File

@@ -0,0 +1,36 @@
1
+package com.chameth.yaotp.algos
2
+
3
+import com.natpryce.hamkrest.assertion.assert
4
+import com.natpryce.hamkrest.equalTo
5
+import org.junit.Test
6
+
7
+class HmacTest {
8
+
9
+    @Test
10
+    fun testHmacSha1_withKnownValues() {
11
+        val key = "key".toByteArray()
12
+        val input = "The quick brown fox jumps over the lazy dog".toByteArray()
13
+        val expected = "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"
14
+
15
+        assert.that(hmacSha1(key, input).toHexString(), equalTo(expected))
16
+    }
17
+
18
+    @Test
19
+    fun testHmacSha256_withKnownValues() {
20
+        val key = "key".toByteArray()
21
+        val input = "The quick brown fox jumps over the lazy dog".toByteArray()
22
+        val expected = "f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8"
23
+
24
+        assert.that(hmacSha256(key, input).toHexString(), equalTo(expected))
25
+    }
26
+
27
+    @Test
28
+    fun testHmacSha512_withKnownValues() {
29
+        val key = "key".toByteArray()
30
+        val input = "The quick brown fox jumps over the lazy dog".toByteArray()
31
+        val expected = "b42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3a"
32
+
33
+        assert.that(hmacSha512(key, input).toHexString(), equalTo(expected))
34
+    }
35
+
36
+}

+ 6
- 1
app/src/test/java/com/chameth/yaotp/algos/HotpTest.kt View File

@@ -9,10 +9,15 @@ class HotpTest {
9 9
     private val rfcByteArray = byteArrayOfInts(0x1f, 0x86, 0x98, 0x69, 0x0e, 0x02, 0xca, 0x16, 0x61, 0x85, 0x50, 0xef, 0x7f, 0x19, 0xda, 0x8e, 0x94, 0x5b, 0x55, 0x5a)
10 10
 
11 11
     @Test
12
-    fun testOffsetValue_returnsLastFourBitsAsInt() {
12
+    fun testOffsetValue_returnsLastFourBitsAsInt_usingRfcValue() {
13 13
         assert.that(offsetValue(rfcByteArray), equalTo(10))
14 14
     }
15 15
 
16
+    @Test
17
+    fun testOffsetValue_returnsLastFourBitsAsInt_usingShorterValue() {
18
+        assert.that(offsetValue(byteArrayOfInts(0x55, 0x5a)), equalTo(10))
19
+    }
20
+
16 21
     @Test
17 22
     fun testOffset_returnsFourBytesAtOffsetValue() {
18 23
         assert.that(offset(rfcByteArray).toHexString(), equalTo("50ef7f19"))

+ 29
- 7
app/src/test/java/com/chameth/yaotp/algos/TotpTest.kt View File

@@ -6,7 +6,9 @@ import org.junit.Test
6 6
 
7 7
 class TotpTest {
8 8
 
9
-    private val rfcKey = "12345678901234567890".toByteArray()
9
+    private val rfcKeySha1 = "12345678901234567890".toByteArray()
10
+    private val rfcKeySha256 = "12345678901234567890123456789012".toByteArray()
11
+    private val rfcKeySha512 = "1234567890123456789012345678901234567890123456789012345678901234".toByteArray()
10 12
 
11 13
     @Test
12 14
     fun testCount_withDefaultStepAndStart_andPastValues() {
@@ -37,12 +39,32 @@ class TotpTest {
37 39
 
38 40
     @Test
39 41
     fun testTotp_withRfcValues_usingSha1() {
40
-        assert.that(totp(rfcKey, 0, 30, 59, 8), equalTo(94287082))
41
-        assert.that(totp(rfcKey, 0, 30, 1111111109, 8), equalTo(7081804))
42
-        assert.that(totp(rfcKey, 0, 30, 1111111111, 8), equalTo(14050471))
43
-        assert.that(totp(rfcKey, 0, 30, 1234567890, 8), equalTo(89005924))
44
-        assert.that(totp(rfcKey, 0, 30, 2000000000, 8), equalTo(69279037))
45
-        assert.that(totp(rfcKey, 0, 30, 20000000000, 8), equalTo(65353130))
42
+        assert.that(totp(rfcKeySha1, 0, 30, 59, 8), equalTo(94287082))
43
+        assert.that(totp(rfcKeySha1, 0, 30, 1111111109, 8), equalTo(7081804))
44
+        assert.that(totp(rfcKeySha1, 0, 30, 1111111111, 8), equalTo(14050471))
45
+        assert.that(totp(rfcKeySha1, 0, 30, 1234567890, 8), equalTo(89005924))
46
+        assert.that(totp(rfcKeySha1, 0, 30, 2000000000, 8), equalTo(69279037))
47
+        assert.that(totp(rfcKeySha1, 0, 30, 20000000000, 8), equalTo(65353130))
48
+    }
49
+
50
+    @Test
51
+    fun testTotp_withRfcValues_usingSha256() {
52
+        assert.that(totp(rfcKeySha256, 0, 30, 59, 8, ::hmacSha256), equalTo(46119246))
53
+        assert.that(totp(rfcKeySha256, 0, 30, 1111111109, 8, ::hmacSha256), equalTo(68084774))
54
+        assert.that(totp(rfcKeySha256, 0, 30, 1111111111, 8, ::hmacSha256), equalTo(67062674))
55
+        assert.that(totp(rfcKeySha256, 0, 30, 1234567890, 8, ::hmacSha256), equalTo(91819424))
56
+        assert.that(totp(rfcKeySha256, 0, 30, 2000000000, 8, ::hmacSha256), equalTo(90698825))
57
+        assert.that(totp(rfcKeySha256, 0, 30, 20000000000, 8, ::hmacSha256), equalTo(77737706))
58
+    }
59
+
60
+    @Test
61
+    fun testTotp_withRfcValues_usingSha512() {
62
+        assert.that(totp(rfcKeySha512, 0, 30, 59, 8, ::hmacSha512), equalTo(90693936))
63
+        assert.that(totp(rfcKeySha512, 0, 30, 1111111109, 8, ::hmacSha512), equalTo(25091201))
64
+        assert.that(totp(rfcKeySha512, 0, 30, 1111111111, 8, ::hmacSha512), equalTo(99943326))
65
+        assert.that(totp(rfcKeySha512, 0, 30, 1234567890, 8, ::hmacSha512), equalTo(93441116))
66
+        assert.that(totp(rfcKeySha512, 0, 30, 2000000000, 8, ::hmacSha512), equalTo(38618901))
67
+        assert.that(totp(rfcKeySha512, 0, 30, 20000000000, 8, ::hmacSha512), equalTo(47863826))
46 68
     }
47 69
 
48 70
 }

+ 0
- 18
app/src/test/java/com/chameth/yaotp/algos/UtilsTest.kt View File

@@ -1,18 +0,0 @@
1
-package com.chameth.yaotp.algos
2
-
3
-import com.natpryce.hamkrest.assertion.assert
4
-import com.natpryce.hamkrest.equalTo
5
-import org.junit.Test
6
-
7
-class UtilsTest {
8
-
9
-    @Test
10
-    fun testHmacSha1_withKnownValues() {
11
-        val key = "key".toByteArray()
12
-        val input = "The quick brown fox jumps over the lazy dog".toByteArray()
13
-        val expected = "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"
14
-
15
-        assert.that(hmacSha1(key, input).toHexString(), equalTo(expected))
16
-    }
17
-
18
-}

Loading…
Cancel
Save