19
19
protocol HashFunctionImplementationDetails : HashFunction where Digest: DigestPrivate { }
20
20
21
21
protocol BoringSSLBackedHashFunction : HashFunctionImplementationDetails {
22
- static var digestType : DigestContext . DigestType { get }
22
+ associatedtype Context
23
+ static var digestSize : Int { get }
24
+ static func initialize( ) -> Context ?
25
+ static func update( _ context: inout Context , data: UnsafeRawBufferPointer ) -> Bool
26
+ static func finalize( _ context: inout Context , digest: UnsafeMutableRawBufferPointer ) -> Bool
23
27
}
24
28
25
29
extension Insecure . MD5 : BoringSSLBackedHashFunction {
26
- static var digestType : DigestContext . DigestType {
27
- . md5
30
+ static var digestSize : Int {
31
+ Int ( MD5_DIGEST_LENGTH)
32
+ }
33
+
34
+ static func initialize( ) -> MD5_CTX ? {
35
+ var context = MD5_CTX ( )
36
+ guard CCryptoBoringSSL_MD5_Init ( & context) == 1 else {
37
+ return nil
38
+ }
39
+ return context
40
+ }
41
+
42
+ static func update( _ context: inout MD5_CTX , data: UnsafeRawBufferPointer ) -> Bool {
43
+ CCryptoBoringSSL_MD5_Update ( & context, data. baseAddress, data. count) == 1
44
+ }
45
+
46
+ static func finalize( _ context: inout MD5_CTX , digest: UnsafeMutableRawBufferPointer ) -> Bool {
47
+ CCryptoBoringSSL_MD5_Final ( digest. baseAddress, & context) == 1
28
48
}
29
49
}
30
50
31
51
extension Insecure . SHA1 : BoringSSLBackedHashFunction {
32
- static var digestType : DigestContext . DigestType {
33
- . sha1
52
+ static var digestSize : Int {
53
+ Int ( SHA_DIGEST_LENGTH)
54
+ }
55
+
56
+ static func initialize( ) -> SHA_CTX ? {
57
+ var context = SHA_CTX ( )
58
+ guard CCryptoBoringSSL_SHA1_Init ( & context) == 1 else {
59
+ return nil
60
+ }
61
+ return context
62
+ }
63
+
64
+ static func update( _ context: inout SHA_CTX , data: UnsafeRawBufferPointer ) -> Bool {
65
+ CCryptoBoringSSL_SHA1_Update ( & context, data. baseAddress, data. count) == 1
66
+ }
67
+
68
+ static func finalize( _ context: inout SHA_CTX , digest: UnsafeMutableRawBufferPointer ) -> Bool {
69
+ CCryptoBoringSSL_SHA1_Final ( digest. baseAddress, & context) == 1
34
70
}
35
71
}
36
72
37
73
extension SHA256 : BoringSSLBackedHashFunction {
38
- static var digestType : DigestContext . DigestType {
39
- . sha256
74
+ static var digestSize : Int {
75
+ Int ( SHA256_DIGEST_LENGTH)
76
+ }
77
+
78
+ static func initialize( ) -> SHA256_CTX ? {
79
+ var context = SHA256_CTX ( )
80
+ guard CCryptoBoringSSL_SHA256_Init ( & context) == 1 else {
81
+ return nil
82
+ }
83
+ return context
84
+ }
85
+
86
+ static func update( _ context: inout SHA256_CTX , data: UnsafeRawBufferPointer ) -> Bool {
87
+ CCryptoBoringSSL_SHA256_Update ( & context, data. baseAddress, data. count) == 1
88
+ }
89
+
90
+ static func finalize( _ context: inout SHA256_CTX , digest: UnsafeMutableRawBufferPointer ) -> Bool {
91
+ CCryptoBoringSSL_SHA256_Final ( digest. baseAddress, & context) == 1
40
92
}
41
93
}
42
94
43
95
extension SHA384 : BoringSSLBackedHashFunction {
44
- static var digestType : DigestContext . DigestType {
45
- . sha384
96
+ static var digestSize : Int {
97
+ Int ( SHA384_DIGEST_LENGTH)
98
+ }
99
+
100
+ static func initialize( ) -> SHA512_CTX ? {
101
+ var context = SHA512_CTX ( )
102
+ guard CCryptoBoringSSL_SHA384_Init ( & context) == 1 else {
103
+ return nil
104
+ }
105
+ return context
106
+ }
107
+
108
+ static func update( _ context: inout SHA512_CTX , data: UnsafeRawBufferPointer ) -> Bool {
109
+ CCryptoBoringSSL_SHA384_Update ( & context, data. baseAddress, data. count) == 1
110
+ }
111
+
112
+ static func finalize( _ context: inout SHA512_CTX , digest: UnsafeMutableRawBufferPointer ) -> Bool {
113
+ CCryptoBoringSSL_SHA384_Final ( digest. baseAddress, & context) == 1
46
114
}
47
115
}
48
116
49
117
extension SHA512 : BoringSSLBackedHashFunction {
50
- static var digestType : DigestContext . DigestType {
51
- . sha512
118
+ static var digestSize : Int {
119
+ Int ( SHA512_DIGEST_LENGTH)
120
+ }
121
+
122
+ static func initialize( ) -> SHA512_CTX ? {
123
+ var context = SHA512_CTX ( )
124
+ guard CCryptoBoringSSL_SHA512_Init ( & context) == 1 else {
125
+ return nil
126
+ }
127
+ return context
128
+ }
129
+
130
+ static func update( _ context: inout SHA512_CTX , data: UnsafeRawBufferPointer ) -> Bool {
131
+ CCryptoBoringSSL_SHA512_Update ( & context, data. baseAddress, data. count) == 1
132
+ }
133
+
134
+ static func finalize( _ context: inout SHA512_CTX , digest: UnsafeMutableRawBufferPointer ) -> Bool {
135
+ CCryptoBoringSSL_SHA512_Final ( digest. baseAddress, & context) == 1
52
136
}
53
137
}
54
138
55
139
struct OpenSSLDigestImpl < H: BoringSSLBackedHashFunction > {
56
- private var context : DigestContext
140
+ private var context : DigestContext < H >
57
141
58
142
init ( ) {
59
- self . context = DigestContext ( digest : H . digestType )
143
+ self . context = DigestContext ( )
60
144
}
61
145
62
146
internal mutating func update( data: UnsafeRawBufferPointer ) {
@@ -67,81 +151,49 @@ struct OpenSSLDigestImpl<H: BoringSSLBackedHashFunction> {
67
151
}
68
152
69
153
internal func finalize( ) -> H . Digest {
70
- // To have a non-destructive finalize operation we must allocate.
71
- let copyContext = DigestContext ( copying: self . context)
72
- let digestBytes = copyContext. finalize ( )
73
- return digestBytes. withUnsafeBytes {
74
- // We force unwrap here because if the digest size is wrong it's an internal error.
75
- H . Digest ( bufferPointer: $0) !
76
- }
154
+ self . context. finalize ( )
77
155
}
78
156
}
79
157
80
- class DigestContext {
81
- private var contextPointer : UnsafeMutablePointer < EVP_MD_CTX >
158
+ fileprivate final class DigestContext < H : BoringSSLBackedHashFunction > {
159
+ private var context : H . Context
82
160
83
- init ( digest: DigestType ) {
84
- // We force unwrap because we cannot recover from allocation failure.
85
- self . contextPointer = CCryptoBoringSSL_EVP_MD_CTX_new ( ) !
86
- guard CCryptoBoringSSL_EVP_DigestInit ( self . contextPointer, digest. dispatchTable) != 0 else {
87
- // We can't do much but crash here.
88
- fatalError ( " Unable to initialize digest state: \( CCryptoBoringSSL_ERR_get_error ( ) ) " )
161
+ init ( ) {
162
+ guard let contex = H . initialize ( ) else {
163
+ preconditionFailure ( " Unable to initialize digest state " )
89
164
}
165
+ self . context = contex
90
166
}
91
167
92
168
init ( copying original: DigestContext ) {
93
- // We force unwrap because we cannot recover from allocation failure.
94
- self . contextPointer = CCryptoBoringSSL_EVP_MD_CTX_new ( ) !
95
- guard CCryptoBoringSSL_EVP_MD_CTX_copy ( self . contextPointer, original. contextPointer) != 0 else {
96
- // We can't do much but crash here.
97
- fatalError ( " Unable to copy digest state: \( CCryptoBoringSSL_ERR_get_error ( ) ) " )
98
- }
169
+ self . context = original. context
99
170
}
100
171
101
172
func update( data: UnsafeRawBufferPointer ) {
102
- guard let baseAddress = data. baseAddress else {
103
- return
173
+ guard H . update ( & self . context , data : data) else {
174
+ preconditionFailure ( " Unable to update digest state " )
104
175
}
105
-
106
- CCryptoBoringSSL_EVP_DigestUpdate ( self . contextPointer, baseAddress, data. count)
107
176
}
108
177
109
- // This finalize function is _destructive_: do not call it if you want to reuse the object!
110
- func finalize( ) -> [ UInt8 ] {
111
- let digestSize = CCryptoBoringSSL_EVP_MD_size ( self . contextPointer. pointee. digest)
112
- var digestBytes = Array ( repeating: UInt8 ( 0 ) , count: digestSize)
113
- var count = UInt32 ( digestSize)
114
-
115
- digestBytes. withUnsafeMutableBufferPointer { digestPointer in
116
- assert ( digestPointer. count == count)
117
- CCryptoBoringSSL_EVP_DigestFinal ( self . contextPointer, digestPointer. baseAddress, & count)
178
+ func finalize( ) -> H . Digest {
179
+ var copyContext = self . context
180
+ defer {
181
+ withUnsafeMutablePointer ( to: & copyContext) { $0. zeroize ( ) }
182
+ }
183
+ return withUnsafeTemporaryAllocation ( byteCount: H . digestSize, alignment: 1 ) { digestPointer in
184
+ defer {
185
+ digestPointer. zeroize ( )
186
+ }
187
+ guard H . finalize ( & copyContext, digest: digestPointer) else {
188
+ preconditionFailure ( " Unable to finalize digest state " )
189
+ }
190
+ // We force unwrap here because if the digest size is wrong it's an internal error.
191
+ return H . Digest ( bufferPointer: UnsafeRawBufferPointer ( digestPointer) ) !
118
192
}
119
-
120
- return digestBytes
121
193
}
122
194
123
195
deinit {
124
- CCryptoBoringSSL_EVP_MD_CTX_free ( self . contextPointer)
125
- }
126
- }
127
-
128
- extension DigestContext {
129
- struct DigestType {
130
- var dispatchTable : OpaquePointer
131
-
132
- private init ( _ dispatchTable: OpaquePointer ) {
133
- self . dispatchTable = dispatchTable
134
- }
135
-
136
- static let md5 = DigestType ( CCryptoBoringSSL_EVP_md5 ( ) )
137
-
138
- static let sha1 = DigestType ( CCryptoBoringSSL_EVP_sha1 ( ) )
139
-
140
- static let sha256 = DigestType ( CCryptoBoringSSL_EVP_sha256 ( ) )
141
-
142
- static let sha384 = DigestType ( CCryptoBoringSSL_EVP_sha384 ( ) )
143
-
144
- static let sha512 = DigestType ( CCryptoBoringSSL_EVP_sha512 ( ) )
196
+ withUnsafeMutablePointer ( to: & self . context) { $0. zeroize ( ) }
145
197
}
146
198
}
147
199
#endif // CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API
0 commit comments