Skip to content

Commit

Permalink
Support Swift 5 (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
djones6 authored and Andrew-Lees11 committed Apr 5, 2019
1 parent 9505013 commit 90ddc20
Show file tree
Hide file tree
Showing 12 changed files with 167 additions and 71 deletions.
2 changes: 1 addition & 1 deletion .swift-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.2.3
5.0
15 changes: 9 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,35 @@ matrix:
dist: xenial
sudo: required
services: docker
env: DOCKER_IMAGE=swift:4.2.3
env: DOCKER_IMAGE=swift:4.2.4 SWIFT_SNAPSHOT=4.2.4
- os: linux
dist: xenial
sudo: required
services: docker
env: DOCKER_IMAGE=swift:4.2.3 SWIFT_SNAPSHOT=$SWIFT_DEVELOPMENT_SNAPSHOT
env: DOCKER_IMAGE=swift:5.0-xenial
- os: linux
dist: xenial
sudo: required
services: docker
env: DOCKER_IMAGE=ubuntu:18.04
env: DOCKER_IMAGE=swift:5.0 SWIFT_SNAPSHOT=$SWIFT_DEVELOPMENT_SNAPSHOT
- os: osx
osx_image: xcode9.4
sudo: required
env: SWIFT_SNAPSHOT=4.1.2
env: SWIFT_SNAPSHOT=4.1.2 JAZZY_ELIGIBLE=true
- os: osx
osx_image: xcode10.1
sudo: required
env: SWIFT_SNAPSHOT=4.2.1
- os: osx
osx_image: xcode10.1
osx_image: xcode10.2
sudo: required
- os: osx
osx_image: xcode10.2
sudo: required
env: SWIFT_SNAPSHOT=$SWIFT_DEVELOPMENT_SNAPSHOT

before_install:
- git clone https://github.com/IBM-Swift/Package-Builder.git

script:
- openssl version
- ./Package-Builder/build-package.sh -projectDir $TRAVIS_BUILD_DIR
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:4.2
// swift-tools-version:5.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
//
// Package.swift
Expand Down
56 changes: 56 additions & 0 deletions [email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// swift-tools-version:4.2
// The swift-tools-version declares the minimum version of Swift required to build this package.
//
// Package.swift
// CryptorECC
//
// Copyright © 2019 IBM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import PackageDescription

var dependencies: [Package.Dependency] = []
var targetDependencies: [Target.Dependency] = []


#if os(Linux)

dependencies.append(.package(url: "https://github.com/IBM-Swift/OpenSSL.git", from: "2.2.2"))
targetDependencies.append(.byName(name: "OpenSSL"))

#endif

let package = Package(
name: "CryptorECC",
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "CryptorECC",
targets: ["CryptorECC"]
)
],
dependencies: dependencies,
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "CryptorECC",
dependencies: targetDependencies
),
.testTarget(
name: "CryptorECCTests",
dependencies: ["CryptorECC"]
)
]
)
39 changes: 39 additions & 0 deletions Sources/CryptorECC/Data+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright © 2019 IBM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation

#if !swift(>=5.0)
// Extension to allow Swift 5 `withUnsafeBytes` API for earlier versions
internal extension Data {
func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T {
let c = count
return try withUnsafeBytes { (p: UnsafePointer<UInt8>) throws -> T in
try body(UnsafeRawBufferPointer(start: p, count: c))
}
}

mutating func withUnsafeMutableBytes<T>(_ body: (UnsafeMutableRawBufferPointer) throws -> T) rethrows -> T {
let c = count
return try withUnsafeMutableBytes { (p: UnsafeMutablePointer<UInt8>) throws -> T in
try body(UnsafeMutableRawBufferPointer(start: p, count: c))
}
}

init(_ bytes: [UInt8]) {
self.init(bytes: bytes)
}
}
#endif
14 changes: 7 additions & 7 deletions Sources/CryptorECC/ECDecryptable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ extension Data {
defer {
EC_POINT_free(pubk_point)
}
encryptedKey.withUnsafeBytes({ (pubk: UnsafePointer<UInt8>) in
let pubk_bn = BN_bin2bn(pubk, Int32(encryptedKey.count), nil)
encryptedKey.withUnsafeBytes({ (pubk: UnsafeRawBufferPointer) in
let pubk_bn = BN_bin2bn(pubk.baseAddress?.assumingMemoryBound(to: UInt8.self), Int32(encryptedKey.count), nil)
let pubk_bn_ctx = BN_CTX_new()
BN_CTX_start(pubk_bn_ctx)
EC_POINT_bn2point(ec_group, pubk_bn, pubk_point, pubk_bn_ctx)
Expand All @@ -85,7 +85,7 @@ extension Data {

// get aes key and iv using ANSI x9.63 Key Derivation Function
let symKeyData = Data(bytes: symKey, count: skey_len)
let counterData = Data(bytes: [0x00, 0x00, 0x00, 0x01])
let counterData = Data([0x00, 0x00, 0x00, 0x01])
let preHashKey = symKeyData + counterData + encryptedKey
let hashedKey = key.curve.digest(data: preHashKey)
let aesKey = [UInt8](hashedKey.subdata(in: 0 ..< 16))
Expand All @@ -109,15 +109,15 @@ extension Data {
}

// Decrypt the encrypted data using the symmetric key.
guard encryptedData.withUnsafeBytes({ (enc: UnsafePointer<UInt8>) -> Int32 in
return EVP_DecryptUpdate(rsaDecryptCtx, decrypted, &processedLen, enc, Int32(encryptedData.count))
guard encryptedData.withUnsafeBytes({ (enc: UnsafeRawBufferPointer) -> Int32 in
return EVP_DecryptUpdate(rsaDecryptCtx, decrypted, &processedLen, enc.baseAddress?.assumingMemoryBound(to: UInt8.self), Int32(encryptedData.count))
}) != 0 else {
throw ECError.failedDecryptionAlgorithm
}
decMsgLen += processedLen
// Verify the provided GCM tag.
guard tagData.withUnsafeMutableBytes({ (tag: UnsafeMutablePointer<UInt8>) -> Int32 in
return EVP_CIPHER_CTX_ctrl(rsaDecryptCtx, EVP_CTRL_GCM_SET_TAG, 16, tag)
guard tagData.withUnsafeMutableBytes({ (tag: UnsafeMutableRawBufferPointer) -> Int32 in
return EVP_CIPHER_CTX_ctrl(rsaDecryptCtx, EVP_CTRL_GCM_SET_TAG, 16, tag.baseAddress)
}) == 1
else {
throw ECError.failedDecryptionAlgorithm
Expand Down
6 changes: 3 additions & 3 deletions Sources/CryptorECC/ECEncryptable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ extension Data: ECEncryptable {

// get aes key and iv using ANSI x9.63 Key Derivation Function
let symKeyData = Data(bytes: symKey, count: symKey_len)
let counterData = Data(bytes: [0x00, 0x00, 0x00, 0x01])
let counterData = Data([0x00, 0x00, 0x00, 0x01])
let sharedInfo = Data(bytes: pubk, count: key.curve.keySize)
let preHashKey = symKeyData + counterData + sharedInfo
let hashedKey = key.curve.digest(data: preHashKey)
Expand Down Expand Up @@ -139,8 +139,8 @@ extension Data: ECEncryptable {
throw ECError.failedDecryptionAlgorithm
}
// Encrypt the plaintext into encrypted using gcmAlgorithm with the random aes key and all 0 iv.
guard(self.withUnsafeBytes({ (plaintext: UnsafePointer<UInt8>) -> Int32 in
return EVP_EncryptUpdate(rsaEncryptCtx, encrypted, &processedLength, plaintext, Int32(self.count))
guard(self.withUnsafeBytes({ (plaintext: UnsafeRawBufferPointer) -> Int32 in
return EVP_EncryptUpdate(rsaEncryptCtx, encrypted, &processedLength, plaintext.baseAddress?.assumingMemoryBound(to: UInt8.self), Int32(self.count))
})) == 1 else {
throw ECError.failedEncryptionAlgorithm
}
Expand Down
78 changes: 39 additions & 39 deletions Sources/CryptorECC/ECPrivateKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -210,20 +210,20 @@ public class ECPrivateKey {
// OBJECT IDENTIFIER
// BIT STRING (This is the `pubKeyBytes` added afterwards)
if self.curve == .prime256v1 {
keyHeader = Data(bytes: [0x30, 0x59,
0x30, 0x13,
0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42])
keyHeader = Data([0x30, 0x59,
0x30, 0x13,
0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42])
} else if self.curve == .secp384r1 {
keyHeader = Data(bytes: [0x30, 0x76,
0x30, 0x10,
0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62])
keyHeader = Data([0x30, 0x76,
0x30, 0x10,
0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22, 0x03, 0x62])
} else if self.curve == .secp521r1 {
keyHeader = Data(bytes: [0x30, 0x81, 0x9B,
0x30, 0x10,
0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23, 0x03, 0x81, 0x86])
keyHeader = Data([0x30, 0x81, 0x9B,
0x30, 0x10,
0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23, 0x03, 0x81, 0x86])
} else {
throw ECError.unsupportedCurve
}
Expand Down Expand Up @@ -372,7 +372,7 @@ public class ECPrivateKey {
}
let keyData = keyBytes as Data
let privateKeyData = keyData.dropFirst(curve.keySize)
let publicKeyData = Data(bytes: [0x00]) + keyData.dropLast(keyData.count - curve.keySize)
let publicKeyData = Data(count: 1) + keyData.dropLast(keyData.count - curve.keySize)
#endif
let derData = ECPrivateKey.generateASN1(privateKey: privateKeyData, publicKey: publicKeyData, curve: curve)
return ECPrivateKey.derToPrivatePEM(derData: derData)
Expand All @@ -389,41 +389,41 @@ public class ECPrivateKey {
// [1] (1 elem)
// BIT STRING (This is the `pubKeyBytes`)
if curve == .prime256v1 {
keyHeader = Data(bytes: [0x30, 0x77,
0x02, 0x01, 0x01,
0x04, 0x20])
keyHeader = Data([0x30, 0x77,
0x02, 0x01, 0x01,
0x04, 0x20])
keyHeader += privateKey
keyHeader += Data(bytes: [0xA0,
0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07,
0xA1,
0x44, 0x03, 0x42])
keyHeader += Data([0xA0,
0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07,
0xA1,
0x44, 0x03, 0x42])
keyHeader += publicKey
} else if curve == .secp384r1 {
keyHeader = Data(bytes: [0x30, 0x81, 0xA4,
0x02, 0x01, 0x01,
0x04, 0x30])
keyHeader = Data([0x30, 0x81, 0xA4,
0x02, 0x01, 0x01,
0x04, 0x30])
keyHeader += privateKey
keyHeader += Data(bytes: [0xA0,
0x07, 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22,
0xA1,
0x64, 0x03, 0x62])
keyHeader += Data([0xA0,
0x07, 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22,
0xA1,
0x64, 0x03, 0x62])
keyHeader += publicKey
} else {
// 521 Private key can be 65 or 66 bytes long
if privateKey.count == 65 {
keyHeader = Data(bytes: [0x30, 0x81, 0xDB,
0x02, 0x01, 0x01,
0x04, 0x41])
keyHeader = Data([0x30, 0x81, 0xDB,
0x02, 0x01, 0x01,
0x04, 0x41])
} else {
keyHeader = Data(bytes: [0x30, 0x81, 0xDC,
0x02, 0x01, 0x01,
0x04, 0x42])
keyHeader = Data([0x30, 0x81, 0xDC,
0x02, 0x01, 0x01,
0x04, 0x42])
}
keyHeader += privateKey
keyHeader += Data(bytes: [0xA0,
0x07, 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23,
0xA1,
0x81, 0x89, 0x03, 0x81, 0x86])
keyHeader += Data([0xA0,
0x07, 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23,
0xA1,
0x81, 0x89, 0x03, 0x81, 0x86])
keyHeader += publicKey
}
return keyHeader
Expand All @@ -435,8 +435,8 @@ public class ECPrivateKey {
defer {
BN_free(bigNum)
}
privateKeyData.withUnsafeBytes({ (privateKeyBytes: UnsafePointer<UInt8>) -> Void in
BN_bin2bn(privateKeyBytes, Int32(privateKeyData.count), bigNum)
privateKeyData.withUnsafeBytes({ (privateKeyBytes: UnsafeRawBufferPointer) -> Void in
BN_bin2bn(privateKeyBytes.baseAddress?.assumingMemoryBound(to: UInt8.self), Int32(privateKeyData.count), bigNum)
})
let ecKey = EC_KEY_new_by_curve_name(curve.nativeCurve)
guard EC_KEY_set_private_key(ecKey, bigNum) == 1 else {
Expand Down
4 changes: 2 additions & 2 deletions Sources/CryptorECC/ECPublicKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ public class ECPublicKey {
defer {
BN_free(bigNum)
}
publicKeyData.withUnsafeBytes({ (pubKeyBytes: UnsafePointer<UInt8>) -> Void in
BN_bin2bn(pubKeyBytes, Int32(publicKeyData.count), bigNum)
publicKeyData.withUnsafeBytes({ (pubKeyBytes: UnsafeRawBufferPointer) -> Void in
BN_bin2bn(pubKeyBytes.baseAddress?.assumingMemoryBound(to: UInt8.self), Int32(publicKeyData.count), bigNum)
})
let ecKey = EC_KEY_new_by_curve_name(curve.nativeCurve)
let ecGroup = EC_KEY_get0_group(ecKey)
Expand Down
5 changes: 2 additions & 3 deletions Sources/CryptorECC/ECSignable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,11 @@ extension Data: ECSignable {
throw ECError.failedEvpInit
}

guard self.withUnsafeBytes({ (message: UnsafePointer<UInt8>) -> Int32 in
return EVP_DigestUpdate(md_ctx, message, self.count)
guard self.withUnsafeBytes({ (message: UnsafeRawBufferPointer) -> Int32 in
return EVP_DigestUpdate(md_ctx, message.baseAddress?.assumingMemoryBound(to: UInt8.self), self.count)
}) == 1 else {
throw ECError.failedSigningAlgorithm
}

var sig_len: Int = 0
EVP_DigestSignFinal(md_ctx, nil, &sig_len)
let sig = UnsafeMutablePointer<UInt8>.allocate(capacity: sig_len)
Expand Down
10 changes: 4 additions & 6 deletions Sources/CryptorECC/ECSignature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,14 @@ public struct ECSignature {
}

EVP_DigestVerifyInit(md_ctx, nil, .make(optional: ecPublicKey.curve.signingAlgorithm), nil, evp_key)
guard plaintext.withUnsafeBytes({ (message: UnsafePointer<UInt8>) -> Int32 in
return EVP_DigestUpdate(md_ctx, message, plaintext.count)
guard plaintext.withUnsafeBytes({ (message: UnsafeRawBufferPointer) -> Int32 in
return EVP_DigestUpdate(md_ctx, message.baseAddress?.assumingMemoryBound(to: UInt8.self), plaintext.count)
}) == 1 else {
return false
}

let rc = self.asn1.withUnsafeBytes({ (sig: UnsafePointer<UInt8>) -> Int32 in
return SSL_EVP_digestVerifyFinal_wrapper(md_ctx, sig, self.asn1.count)
let rc = self.asn1.withUnsafeBytes({ (sig: UnsafeRawBufferPointer) -> Int32 in
return SSL_EVP_digestVerifyFinal_wrapper(md_ctx, sig.baseAddress?.assumingMemoryBound(to: UInt8.self), self.asn1.count)
})

return rc == 1
#else
let hash = ecPublicKey.curve.digest(data: plaintext)
Expand Down
7 changes: 4 additions & 3 deletions Sources/CryptorECC/EllipticCurve.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,11 @@ public struct EllipticCurve: Equatable, CustomStringConvertible {
func digest(data: Data) -> Data {

var hash = [UInt8](repeating: 0, count: Int(self.hashLength))
data.withUnsafeBytes {
_ = self.hashEngine($0, CC_LONG(data.count), &hash)
data.withUnsafeBytes { ptr in
guard let baseAddress = ptr.baseAddress else { return }
_ = self.hashEngine(baseAddress.assumingMemoryBound(to: UInt8.self), CC_LONG(data.count), &hash)
}
return Data(bytes: hash)
return Data(hash)
}
}

Expand Down

0 comments on commit 90ddc20

Please sign in to comment.