File: HKDF.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (166 lines) | stat: -rw-r--r-- 7,770 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftCrypto open source project
//
// Copyright (c) 2019-2020 Apple Inc. and the SwiftCrypto project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.md for the list of SwiftCrypto project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
#if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API
@_exported import CryptoKit
#else
import Foundation

/// A standards-based implementation of an HMAC-based Key Derivation Function
/// (HKDF).
///
/// The key derivation functions allow you to derive one or more secrets of the
/// size of your choice from a main key or passcode. The key derivation function
/// is compliant with IETF RFC 5869. Use one of the `deriveKey` functions, such
/// as ``deriveKey(inputKeyMaterial:outputByteCount:)`` or
/// ``deriveKey(inputKeyMaterial:salt:info:outputByteCount:)``, to derive a key
/// from a main secret or passcode in a single function.
///
/// To derive a key with more fine-grained control, use
/// ``extract(inputKeyMaterial:salt:)`` to create cryptographically strong key
/// material in the form of a hashed authentication code, then call
/// ``expand(pseudoRandomKey:info:outputByteCount:)`` using that key material to
/// generate a symmetric key of the length you specify.
public struct HKDF<H: HashFunction> {
    /// Derives a symmetric encryption key from a main key or passcode using
    /// HKDF key derivation with information and salt you specify.
    ///
    /// - Parameters:
    ///   - inputKeyMaterial: The main key or passcode the derivation function
    /// uses to derive a key.
    ///   - salt: The salt to use for key derivation.
    ///   - info: The shared information to use for key derivation.
    ///   - outputByteCount: The length in bytes of the resulting symmetric key.
    ///
    /// - Returns: The derived symmetric key.
    public static func deriveKey<Salt: DataProtocol, Info: DataProtocol>(inputKeyMaterial: SymmetricKey,
                                                                         salt: Salt,
                                                                         info: Info,
                                                                         outputByteCount: Int) -> SymmetricKey {
        return expand(pseudoRandomKey: extract(inputKeyMaterial: inputKeyMaterial, salt: salt), info: info, outputByteCount: outputByteCount)
    }
    
    /// Derives a symmetric encryption key from a main key or passcode using
    /// HKDF key derivation with information you specify.
    ///
    /// - Parameters:
    ///   - inputKeyMaterial: The main key or passcode the derivation function
    /// uses to derive a key.
    ///   - info: The shared information to use for key derivation.
    ///   - outputByteCount: The length in bytes of the resulting symmetric key.
    ///
    /// - Returns: The derived symmetric key.
    public static func deriveKey<Info: DataProtocol>(inputKeyMaterial: SymmetricKey,
                                                     info: Info,
                                                     outputByteCount: Int) -> SymmetricKey {
        return deriveKey(inputKeyMaterial: inputKeyMaterial, salt: [UInt8](), info: info, outputByteCount: outputByteCount)
    }
    
    /// Derives a symmetric encryption key from a main key or passcode using
    /// HKDF key derivation with salt that you specify.
    ///
    /// - Parameters:
    ///   - inputKeyMaterial: The main key or passcode the derivation function
    /// uses to derive a key.
    ///   - salt: The salt to use for key derivation.
    ///   - outputByteCount: The length in bytes of the resulting symmetric key.
    ///
    /// - Returns: The derived symmetric key.
    public static func deriveKey<Salt: DataProtocol>(inputKeyMaterial: SymmetricKey,
                                                     salt: Salt,
                                                     outputByteCount: Int) -> SymmetricKey {
        return deriveKey(inputKeyMaterial: inputKeyMaterial, salt: salt, info: [UInt8](), outputByteCount: outputByteCount)
    }
    
    /// Derives a symmetric encryption key from a main key or passcode using
    /// HKDF key derivation.
    ///
    /// - Parameters:
    ///   - inputKeyMaterial: The main key or passcode the derivation function
    /// uses to derive a key.
    ///   - outputByteCount: The length in bytes of the resulting symmetric key.
    ///
    /// - Returns: The derived symmetric key.
    public static func deriveKey(inputKeyMaterial: SymmetricKey,
                                 outputByteCount: Int) -> SymmetricKey {
        return deriveKey(inputKeyMaterial: inputKeyMaterial, salt: [UInt8](), info: [UInt8](), outputByteCount: outputByteCount)
    }
    
    /// Creates cryptographically strong key material from a main key or
    /// passcode that you specify.
    ///
    /// Generate a derived symmetric key from the cryptographically strong key
    /// material this function creates by calling
    /// ``expand(pseudoRandomKey:info:outputByteCount:)``.
    ///
    /// - Parameters:
    ///   - inputKeyMaterial: The main key or passcode the derivation function
    /// uses to derive a key.
    ///   - salt: The salt to use for key derivation.
    ///
    /// - Returns: A pseudorandom, cryptographically strong key in the form of a
    /// hashed authentication code.
    public static func extract<Salt: DataProtocol>(inputKeyMaterial: SymmetricKey, salt: Salt?) -> HashedAuthenticationCode<H> {
        let key: SymmetricKey
        if let salt = salt {
            if salt.regions.count != 1 {
                let contiguousBytes = Array(salt)
                key = SymmetricKey(data: contiguousBytes)
            } else {
                key = SymmetricKey(data: salt.regions.first!)
            }
        } else {
            key = SymmetricKey(data: [UInt8]())
        }
        
        return inputKeyMaterial.withUnsafeBytes { ikmBytes in
            return HMAC<H>.authenticationCode(for: ikmBytes, using: key)
        }
    }
    
    /// Expands cryptographically strong key material into a derived symmetric
    /// key.
    ///
    /// Generate cryptographically strong key material to use with this function
    /// by calling ``extract(inputKeyMaterial:salt:)``.
    ///
    /// - Parameters:
    ///   - prk: A pseudorandom, cryptographically strong key generated from the
    /// ``extract(inputKeyMaterial:salt:)`` function.
    ///   - info: The shared information to use for key derivation.
    ///   - outputByteCount: The length in bytes of the resulting symmetric key.
    ///
    /// - Returns: The derived symmetric key.
    public static func expand<PRK: ContiguousBytes, Info: DataProtocol>(pseudoRandomKey prk: PRK, info: Info?, outputByteCount: Int) -> SymmetricKey {
        let iterations: UInt8 = UInt8(ceil((Float(outputByteCount) / Float(H.Digest.byteCount))))
        var output = SecureBytes()
        let key = SymmetricKey(data: prk)
        var TMinusOne = SecureBytes()
        for i in 1...iterations {
            var hmac = HMAC<H>(key: key)
            hmac.update(data: TMinusOne)
            if let info = info {
                hmac.update(data: info)
            }
            
            withUnsafeBytes(of: i) { counter in
                hmac.update(bufferPointer: counter)
            }
            TMinusOne = SecureBytes(hmac.finalize())
            output.append(TMinusOne)
        }
        
        return SymmetricKey(data: output.prefix(outputByteCount))
    }
}
#endif // Linux or !SwiftPM