Skip to content

Commit 8da0317

Browse files
committed
[Issue #77] Remove md2, md4, and md5 for all Apple platforms
* Address the deprecation warning due to Apple considering them insecure * Update platform versions (cocoapods / SPM): * MacOS - 11 / 11.5 * iOS - 14 / 14.5 * tvOS - 14 / 14.5 * watchOS - 7 / 7.5 * Update Swift Version to 5.4 * Keep md4 & md5 for Linux * Add md5_insecure & sha1_insecure to mimic the Apple APIs
1 parent 3e8dd1d commit 8da0317

File tree

6 files changed

+242
-110
lines changed

6 files changed

+242
-110
lines changed

BlueCryptor.podspec

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
Pod::Spec.new do |s|
22
s.name = "BlueCryptor"
3-
s.version = "2.0.3"
3+
s.version = "2.1.0"
44
s.summary = "Swift cross-platform crypto library using CommonCrypto/libcrypto via Package Manager."
55
s.homepage = "https://github.com/Kitura/BlueCryptor"
66
s.license = { :type => "Apache License, Version 2.0" }
77
s.author = "IBM & Kitura Project Authors"
88
s.module_name = 'Cryptor'
99

1010
s.requires_arc = true
11-
s.swift_version = '5.1'
12-
s.osx.deployment_target = "10.11"
13-
s.ios.deployment_target = "10.0"
14-
s.tvos.deployment_target = "10.0"
15-
s.watchos.deployment_target = "2.0"
11+
s.swift_version = '5.4'
12+
s.osx.deployment_target = "11.5"
13+
s.ios.deployment_target = "14.5"
14+
s.tvos.deployment_target = "14.5"
15+
s.watchos.deployment_target = "7.5"
1616
s.source = { :git => "https://github.com/Kitura/BlueCryptor.git", :tag => s.version }
1717
s.source_files = "Sources/Cryptor/*.swift"
1818
s.pod_target_xcconfig = {
19-
'SWIFT_VERSION' => '5.0',
19+
'SWIFT_VERSION' => '5.4',
2020
}
2121
end

Package.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.0
1+
// swift-tools-version:5.4
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
//
@@ -33,10 +33,10 @@ var targetDependencies: [Target.Dependency] = []
3333
let package = Package(
3434
name: "Cryptor",
3535
platforms: [
36-
.macOS(.v10_11),
37-
.iOS(.v10),
38-
.tvOS(.v10),
39-
.watchOS(.v2),
36+
.macOS(.v11),
37+
.iOS(.v14),
38+
.tvOS(.v14),
39+
.watchOS(.v7),
4040
],
4141
products: [
4242
// Products define the executables and libraries produced by a package, and make them visible to other packages.
@@ -53,5 +53,5 @@ let package = Package(
5353
name: "CryptorTests",
5454
dependencies: ["Cryptor"]),
5555
],
56-
swiftLanguageVersions: [.v5]
56+
swiftLanguageVersions: [SwiftVersion.version("5.4")]
5757
)

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,10 @@ Also provided are an API to pad a byte array (`[UInt8]`) such that it is an inte
211211

212212
## Restrictions
213213

214-
The following algorithm is not available on Linux since it is not supported by *OpenSSL*.
215-
- Digest: MD2
214+
The following algorithms are only available on Linux since Apple considers them cryptographically broken
215+
- Digest: MD4
216+
- Digest: MD5
217+
- MD5 is available as an insecure algorithm
216218

217219
In all cases, use of unsupported APIs or algorithms will result in a Swift `fatalError()`, terminating the program and should be treated as a programming error.
218220

Sources/Cryptor/Crypto.swift

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,35 @@ public protocol CryptoDigest {
3030
/// Extension to the CryptoDigest to return the digest appropriate to the selected algorithm.
3131
///
3232
extension CryptoDigest {
33-
34-
/// An MD2 digest of this object
35-
public var md2: Self {
36-
return self.digest(using: .md2)
37-
}
38-
39-
/// An MD4 digest of this object
40-
public var md4: Self {
41-
return self.digest(using: .md4)
42-
}
43-
44-
/// An MD5 digest of this object
45-
public var md5: Self {
46-
return self.digest(using: .md5)
47-
}
48-
33+
34+
// Only available on Linux as Apple platforms consider them cryptographically insecure
35+
#if os(Linux)
36+
/// An MD4 digest of this object
37+
public var md4: Self {
38+
return self.digest(using: .md4)
39+
}
40+
41+
/// An MD5 digest of this object
42+
public var md5: Self {
43+
return self.digest(using: .md5)
44+
}
45+
#endif
46+
47+
/// An MD5 digest of this object. Called out as "insecure" as it should not be used for cryptographic purposes
48+
public var md5_insecure: Self {
49+
return self.digest(using: .md5_insecure)
50+
}
51+
4952
/// An SHA1 digest of this object
5053
public var sha1: Self {
5154
return self.digest(using: .sha1)
5255
}
5356

57+
/// An SHA1 digest of this object. Called out as "insecure" as it should not be used for cryptographic purposes
58+
public var sha1_insecure: Self {
59+
return self.digest(using: .sha1_insecure)
60+
}
61+
5462
/// An SHA224 digest of this object
5563
public var sha224: Self {
5664
return self.digest(using: .sha224)

Sources/Cryptor/Digest.swift

Lines changed: 108 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ import Foundation
2222
typealias CC_LONG = size_t
2323
#else
2424
import CommonCrypto
25+
#if canImport(CryptoKit)
26+
import CryptoKit
27+
#endif
2528
#endif
2629

2730
///
@@ -50,18 +53,26 @@ public class Digest: Updatable {
5053
///
5154
public enum Algorithm {
5255

53-
/// Message Digest 2 See: http://en.wikipedia.org/wiki/MD2_(cryptography)
54-
case md2
55-
56-
/// Message Digest 4
57-
case md4
58-
56+
// Only available on Linux as Apple platforms consider them cryptographically insecure
57+
#if os(Linux)
58+
/// Message Digest 4
59+
case md4
60+
61+
/// Message Digest 5
62+
case md5
63+
#endif
64+
5965
/// Message Digest 5
60-
case md5
61-
66+
/// - NOTE: Do NOT use for cryptography, considered insecure
67+
case md5_insecure
68+
6269
/// Secure Hash Algorithm 1
6370
case sha1
64-
71+
72+
/// Secure Hash Algorithm 1
73+
/// - NOTE: Do NOT use for cryptography, considered insecure
74+
case sha1_insecure
75+
6576
/// Secure Hash Algorithm 2 224-bit
6677
case sha224
6778

@@ -85,61 +96,61 @@ public class Digest: Updatable {
8596
public init(using algorithm: Algorithm) {
8697

8798
switch algorithm {
99+
100+
#if os(Linux)
101+
case .md4:
102+
self.engine = DigestEngineCC<MD4_CTX>(initializer:MD4_Init, updater:MD4_Update, finalizer:MD4_Final, length:MD4_DIGEST_LENGTH)
103+
104+
case .md5, .md5_insecure:
105+
self.engine = DigestEngineCC<MD5_CTX>(initializer:MD5_Init, updater:MD5_Update, finalizer:MD5_Final, length:MD5_DIGEST_LENGTH)
106+
107+
#else
88108

89-
case .md2:
90-
#if os(Linux)
91-
fatalError("MD2 digest not supported by OpenSSL")
92-
#else
93-
engine = DigestEngineCC<CC_MD2_CTX>(initializer:CC_MD2_Init, updater:CC_MD2_Update, finalizer:CC_MD2_Final, length:CC_MD2_DIGEST_LENGTH)
94-
#endif
95-
96-
case .md4:
97-
#if os(Linux)
98-
engine = DigestEngineCC<MD4_CTX>(initializer:MD4_Init, updater:MD4_Update, finalizer:MD4_Final, length:MD4_DIGEST_LENGTH)
99-
#else
100-
engine = DigestEngineCC<CC_MD4_CTX>(initializer:CC_MD4_Init, updater:CC_MD4_Update, finalizer:CC_MD4_Final, length:CC_MD4_DIGEST_LENGTH)
101-
#endif
102-
103-
case .md5:
104-
#if os(Linux)
105-
engine = DigestEngineCC<MD5_CTX>(initializer:MD5_Init, updater:MD5_Update, finalizer:MD5_Final, length:MD5_DIGEST_LENGTH)
106-
#else
107-
engine = DigestEngineCC<CC_MD5_CTX>(initializer:CC_MD5_Init, updater:CC_MD5_Update, finalizer:CC_MD5_Final, length:CC_MD5_DIGEST_LENGTH)
108-
#endif
109-
109+
case .md5_insecure:
110+
self.engine = DigestEngineMD5Insecure()
111+
112+
#endif
113+
110114
case .sha1:
111115
#if os(Linux)
112-
engine = DigestEngineCC<SHA_CTX>(initializer:SHA1_Init, updater:SHA1_Update, finalizer:SHA1_Final, length:SHA_DIGEST_LENGTH)
116+
self.engine = DigestEngineCC<SHA_CTX>(initializer:SHA1_Init, updater:SHA1_Update, finalizer:SHA1_Final, length:SHA_DIGEST_LENGTH)
113117
#else
114118
engine = DigestEngineCC<CC_SHA1_CTX>(initializer:CC_SHA1_Init, updater:CC_SHA1_Update, finalizer:CC_SHA1_Final, length:CC_SHA1_DIGEST_LENGTH)
115-
#endif
116-
119+
#endif
120+
121+
case .sha1_insecure:
122+
#if os(Linux)
123+
self.engine = DigestEngineCC<SHA_CTX>(initializer:SHA1_Init, updater:SHA1_Update, finalizer:SHA1_Final, length:SHA_DIGEST_LENGTH)
124+
#else
125+
self.engine = DigestEngineSHA1Insecure()
126+
#endif
127+
117128
case .sha224:
118129
#if os(Linux)
119-
engine = DigestEngineCC<SHA256_CTX>(initializer:SHA224_Init, updater:SHA224_Update, finalizer:SHA224_Final, length:SHA224_DIGEST_LENGTH)
130+
self.engine = DigestEngineCC<SHA256_CTX>(initializer:SHA224_Init, updater:SHA224_Update, finalizer:SHA224_Final, length:SHA224_DIGEST_LENGTH)
120131
#else
121-
engine = DigestEngineCC<CC_SHA256_CTX>(initializer:CC_SHA224_Init, updater:CC_SHA224_Update, finalizer:CC_SHA224_Final, length:CC_SHA224_DIGEST_LENGTH)
132+
self.engine = DigestEngineCC<CC_SHA256_CTX>(initializer:CC_SHA224_Init, updater:CC_SHA224_Update, finalizer:CC_SHA224_Final, length:CC_SHA224_DIGEST_LENGTH)
122133
#endif
123134

124135
case .sha256:
125136
#if os(Linux)
126-
engine = DigestEngineCC<SHA256_CTX>(initializer: SHA256_Init, updater:SHA256_Update, finalizer:SHA256_Final, length:SHA256_DIGEST_LENGTH)
137+
self.engine = DigestEngineCC<SHA256_CTX>(initializer: SHA256_Init, updater:SHA256_Update, finalizer:SHA256_Final, length:SHA256_DIGEST_LENGTH)
127138
#else
128-
engine = DigestEngineCC<CC_SHA256_CTX>(initializer:CC_SHA256_Init, updater:CC_SHA256_Update, finalizer:CC_SHA256_Final, length:CC_SHA256_DIGEST_LENGTH)
139+
self.engine = DigestEngineCC<CC_SHA256_CTX>(initializer:CC_SHA256_Init, updater:CC_SHA256_Update, finalizer:CC_SHA256_Final, length:CC_SHA256_DIGEST_LENGTH)
129140
#endif
130141

131142
case .sha384:
132143
#if os(Linux)
133-
engine = DigestEngineCC<SHA512_CTX>(initializer:SHA384_Init, updater:SHA384_Update, finalizer:SHA384_Final, length:SHA384_DIGEST_LENGTH)
144+
self.engine = DigestEngineCC<SHA512_CTX>(initializer:SHA384_Init, updater:SHA384_Update, finalizer:SHA384_Final, length:SHA384_DIGEST_LENGTH)
134145
#else
135-
engine = DigestEngineCC<CC_SHA512_CTX>(initializer:CC_SHA384_Init, updater:CC_SHA384_Update, finalizer:CC_SHA384_Final, length:CC_SHA384_DIGEST_LENGTH)
146+
self.engine = DigestEngineCC<CC_SHA512_CTX>(initializer:CC_SHA384_Init, updater:CC_SHA384_Update, finalizer:CC_SHA384_Final, length:CC_SHA384_DIGEST_LENGTH)
136147
#endif
137148

138149
case .sha512:
139150
#if os(Linux)
140-
engine = DigestEngineCC<SHA512_CTX>(initializer:SHA512_Init, updater:SHA512_Update, finalizer:SHA512_Final, length:SHA512_DIGEST_LENGTH)
151+
self.engine = DigestEngineCC<SHA512_CTX>(initializer:SHA512_Init, updater:SHA512_Update, finalizer:SHA512_Final, length:SHA512_DIGEST_LENGTH)
141152
#else
142-
engine = DigestEngineCC<CC_SHA512_CTX>(initializer:CC_SHA512_Init, updater:CC_SHA512_Update, finalizer:CC_SHA512_Final, length:CC_SHA512_DIGEST_LENGTH)
153+
self.engine = DigestEngineCC<CC_SHA512_CTX>(initializer:CC_SHA512_Init, updater:CC_SHA512_Update, finalizer:CC_SHA512_Final, length:CC_SHA512_DIGEST_LENGTH)
143154
#endif
144155
}
145156
}
@@ -269,6 +280,62 @@ private class DigestEngineCC<CTX>: DigestEngine {
269280
}
270281

271282

283+
#if !os(Linux)
272284

285+
/**
286+
Wraps the Insecure.MD5 engine as a DigestEngine
287+
*/
288+
private class DigestEngineMD5Insecure: DigestEngine {
289+
var engine = Insecure.MD5()
290+
291+
func update(buffer: UnsafeRawPointer, byteCount: CC_LONG) {
292+
guard byteCount<=Int.max else {
293+
fatalError("Cannot support byte count of size: \(byteCount)")
294+
}
295+
let count = Int(byteCount)
296+
let bufferPointer = UnsafeRawBufferPointer(start: buffer, count: count)
297+
engine.update(bufferPointer: bufferPointer)
298+
}
299+
300+
func final() -> [UInt8] {
301+
let digest: Insecure.MD5Digest = self.engine.finalize()
302+
let digestLength = Int(Insecure.MD5Digest.byteCount)
303+
var buffer = Array<UInt8>(repeating: 0, count:digestLength)
304+
digest.withUnsafeBytes { (rawBuffer: UnsafeRawBufferPointer) in
305+
for (index, val) in rawBuffer.enumerated() {
306+
buffer[index] = val
307+
}
308+
}
309+
return buffer
310+
}
311+
}
273312

313+
/**
314+
Wraps the Insecure.SHA1 engine as a DigestEngine
315+
*/
316+
private class DigestEngineSHA1Insecure: DigestEngine {
317+
var engine = Insecure.SHA1()
318+
319+
func update(buffer: UnsafeRawPointer, byteCount: CC_LONG) {
320+
guard byteCount<=Int.max else {
321+
fatalError("Cannot support byte count of size: \(byteCount)")
322+
}
323+
let count = Int(byteCount)
324+
let bufferPointer = UnsafeRawBufferPointer(start: buffer, count: count)
325+
engine.update(bufferPointer: bufferPointer)
326+
}
327+
328+
func final() -> [UInt8] {
329+
let digest: Insecure.SHA1Digest = self.engine.finalize()
330+
let digestLength = Int(Insecure.SHA1Digest.byteCount)
331+
var buffer = Array<UInt8>(repeating: 0, count:digestLength)
332+
digest.withUnsafeBytes { (rawBuffer: UnsafeRawBufferPointer) in
333+
for (index, val) in rawBuffer.enumerated() {
334+
buffer[index] = val
335+
}
336+
}
337+
return buffer
338+
}
339+
}
274340

341+
#endif

0 commit comments

Comments
 (0)