Skip to content

Commit e96c62d

Browse files
committed
CryptoKit HKDF implementation
1 parent 667edbf commit e96c62d

File tree

5 files changed

+128
-13
lines changed

5 files changed

+128
-13
lines changed

cryptography-providers/cryptokit/src/commonMain/kotlin/CryptoKitCryptographyProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ internal object CryptoKitCryptographyProvider : CryptographyProvider() {
2626
SHA384 -> CryptoKitDigest(SHA384, SwiftHash::sha384, SwiftHashAlgorithmSha384)
2727
SHA512 -> CryptoKitDigest(SHA512, SwiftHash::sha512, SwiftHashAlgorithmSha512)
2828
HMAC -> CryptoKitHmac
29-
// HKDF ->
29+
HKDF -> CryptoKitHkdf
3030
// AES.GCM ->
3131
// ECDSA ->
3232
// ECDH ->
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (c) 2024-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package dev.whyoleg.cryptography.providers.cryptokit.algorithms
6+
7+
import dev.whyoleg.cryptography.*
8+
import dev.whyoleg.cryptography.algorithms.*
9+
import dev.whyoleg.cryptography.operations.*
10+
import dev.whyoleg.cryptography.providers.base.*
11+
import dev.whyoleg.cryptography.providers.cryptokit.internal.swiftinterop.*
12+
import kotlinx.cinterop.*
13+
14+
@OptIn(UnsafeNumber::class)
15+
internal object CryptoKitHkdf : HKDF {
16+
override fun secretDerivation(
17+
digest: CryptographyAlgorithmId<Digest>,
18+
outputSize: BinarySize,
19+
salt: ByteArray?,
20+
info: ByteArray?,
21+
): SecretDerivation = HkdfSecretDerivation(
22+
algorithm = when (digest) {
23+
MD5 -> SwiftHashAlgorithmMd5
24+
SHA1 -> SwiftHashAlgorithmSha1
25+
SHA256 -> SwiftHashAlgorithmSha256
26+
SHA384 -> SwiftHashAlgorithmSha384
27+
SHA512 -> SwiftHashAlgorithmSha512
28+
else -> throw IllegalStateException("Unsupported hash algorithm: $digest")
29+
},
30+
outputSize = outputSize,
31+
salt = salt ?: EmptyByteArray,
32+
info = info ?: EmptyByteArray
33+
)
34+
}
35+
36+
@OptIn(UnsafeNumber::class)
37+
private class HkdfSecretDerivation(
38+
private val algorithm: SwiftHashAlgorithm,
39+
private val outputSize: BinarySize,
40+
private val salt: ByteArray,
41+
private val info: ByteArray,
42+
) : SecretDerivation {
43+
override fun deriveSecretToByteArrayBlocking(input: ByteArray): ByteArray {
44+
return input.useNSData { ikm ->
45+
salt.useNSData { salt ->
46+
info.useNSData { info ->
47+
SwiftHkdf.derive(
48+
algorithm,
49+
ikm,
50+
salt,
51+
info,
52+
outputSize.inBytes.convert()
53+
).toByteArray()
54+
}
55+
}
56+
}
57+
}
58+
}

cryptography-providers/cryptokit/src/commonMain/swift/SwiftHash.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ import Foundation
3333

3434
@objc public init(algorithm: SwiftHashAlgorithm) {
3535
self.algorithm = algorithm
36-
switch algorithm {
37-
case .md5: function = Insecure.MD5()
38-
case .sha1: function = Insecure.SHA1()
39-
case .sha256: function = SHA256()
40-
case .sha384: function = SHA384()
41-
case .sha512: function = SHA512()
36+
self.function = switch algorithm {
37+
case .md5: Insecure.MD5()
38+
case .sha1: Insecure.SHA1()
39+
case .sha256: SHA256()
40+
case .sha384: SHA384()
41+
case .sha512: SHA512()
4242
}
4343
super.init()
4444
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import CryptoKit
2+
import Foundation
3+
4+
@objc public class SwiftHkdf: NSObject {
5+
6+
@objc(derive:::::) public static func derive(
7+
algorithm: SwiftHashAlgorithm,
8+
inputKey: NSData,
9+
salt: NSData,
10+
info: NSData,
11+
outputSize: Int
12+
) -> Data {
13+
let ikm = SymmetricKey(data: inputKey as Data)
14+
let outputKey = switch algorithm {
15+
case .md5:
16+
HKDF<Insecure.MD5>.deriveKey(
17+
inputKeyMaterial: ikm,
18+
salt: salt,
19+
info: info,
20+
outputByteCount: outputSize
21+
)
22+
23+
case .sha1:
24+
HKDF<Insecure.SHA1>.deriveKey(
25+
inputKeyMaterial: ikm,
26+
salt: salt,
27+
info: info,
28+
outputByteCount: outputSize
29+
)
30+
31+
case .sha256:
32+
HKDF<SHA256>.deriveKey(
33+
inputKeyMaterial: ikm,
34+
salt: salt,
35+
info: info,
36+
outputByteCount: outputSize
37+
)
38+
39+
case .sha384:
40+
HKDF<SHA384>.deriveKey(
41+
inputKeyMaterial: ikm,
42+
salt: salt,
43+
info: info,
44+
outputByteCount: outputSize
45+
)
46+
47+
case .sha512:
48+
HKDF<SHA512>.deriveKey(
49+
inputKeyMaterial: ikm,
50+
salt: salt,
51+
info: info,
52+
outputByteCount: outputSize
53+
)
54+
}
55+
return outputKey.withUnsafeBytes { Data($0) }
56+
}
57+
}

cryptography-providers/cryptokit/src/commonMain/swift/SwiftHmac.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import Foundation
66

77
@objc public init(algorithm: SwiftHashAlgorithm, key: NSData) {
88
let secretKey = SymmetricKey(data: key as Data)
9-
switch algorithm {
10-
case .md5: wrapper = HmacWrapper<Insecure.MD5>(key: secretKey)
11-
case .sha1: wrapper = HmacWrapper<Insecure.SHA1>(key: secretKey)
12-
case .sha256: wrapper = HmacWrapper<SHA256>(key: secretKey)
13-
case .sha384: wrapper = HmacWrapper<SHA384>(key: secretKey)
14-
case .sha512: wrapper = HmacWrapper<SHA512>(key: secretKey)
9+
self.wrapper = switch algorithm {
10+
case .md5: HmacWrapper<Insecure.MD5>(key: secretKey)
11+
case .sha1: HmacWrapper<Insecure.SHA1>(key: secretKey)
12+
case .sha256: HmacWrapper<SHA256>(key: secretKey)
13+
case .sha384: HmacWrapper<SHA384>(key: secretKey)
14+
case .sha512: HmacWrapper<SHA512>(key: secretKey)
1515
}
1616
super.init()
1717
}

0 commit comments

Comments
 (0)