Initial commit
This commit is contained in:
1111
Pods/BlueRSA/Sources/CryptorRSA/CryptorRSA.swift
generated
Normal file
1111
Pods/BlueRSA/Sources/CryptorRSA/CryptorRSA.swift
generated
Normal file
File diff suppressed because it is too large
Load Diff
74
Pods/BlueRSA/Sources/CryptorRSA/CryptorRSAConstants.swift
generated
Normal file
74
Pods/BlueRSA/Sources/CryptorRSA/CryptorRSAConstants.swift
generated
Normal file
@ -0,0 +1,74 @@
|
||||
//
|
||||
// CryptorRSAConstants.swift
|
||||
// CryptorRSA
|
||||
//
|
||||
// Created by Bill Abt on 1/18/17.
|
||||
//
|
||||
// Copyright © 2017 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
|
||||
|
||||
// MARK: -
|
||||
|
||||
@available(macOS 10.12, iOS 10.3, watchOS 3.3, tvOS 12.0, *)
|
||||
public extension CryptorRSA {
|
||||
|
||||
// MARK: Constants
|
||||
|
||||
// MARK: Certificate Suffixes
|
||||
|
||||
/// X509 Certificate Extension
|
||||
static let CER_SUFFIX: String = ".cer"
|
||||
|
||||
/// PEM Suffix
|
||||
static let PEM_SUFFIX: String = ".pem"
|
||||
|
||||
/// DER Suffix
|
||||
static let DER_SUFFIX: String = ".der"
|
||||
|
||||
// MARK: PEM Certificate Markers
|
||||
|
||||
/// PEM Begin Marker
|
||||
static let PEM_BEGIN_MARKER: String = "-----BEGIN CERTIFICATE-----"
|
||||
|
||||
/// PEM End Marker
|
||||
static let PEM_END_MARKER: String = "-----END CERTIFICATE-----"
|
||||
|
||||
// MARK: Public Key Markers
|
||||
|
||||
/// PK Begin Marker
|
||||
static let PK_BEGIN_MARKER: String = "-----BEGIN PUBLIC KEY-----"
|
||||
|
||||
/// PK End Marker
|
||||
static let PK_END_MARKER: String = "-----END PUBLIC KEY-----"
|
||||
|
||||
// MARK: Private Key Markers
|
||||
|
||||
/// SK Begin Marker
|
||||
static let SK_BEGIN_MARKER: String = "-----BEGIN RSA PRIVATE KEY-----"
|
||||
|
||||
/// SK End Marker
|
||||
static let SK_END_MARKER: String = "-----END RSA PRIVATE KEY-----"
|
||||
|
||||
// MARK: Generic Key Markers
|
||||
|
||||
/// Generic Begin Marker
|
||||
static let GENERIC_BEGIN_MARKER: String = "-----BEGIN"
|
||||
|
||||
/// Generic End Marker
|
||||
static let GENERIC_END_MARKER: String = "-----END"
|
||||
|
||||
}
|
||||
329
Pods/BlueRSA/Sources/CryptorRSA/CryptorRSADigest.swift
generated
Normal file
329
Pods/BlueRSA/Sources/CryptorRSA/CryptorRSADigest.swift
generated
Normal file
@ -0,0 +1,329 @@
|
||||
//
|
||||
// CryptorRSADigest.swift
|
||||
// CryptorRSA
|
||||
//
|
||||
// Created by Bill Abt on 1/18/17.
|
||||
//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
import CommonCrypto
|
||||
#elseif os(Linux)
|
||||
import OpenSSL
|
||||
public typealias CC_LONG = size_t
|
||||
#endif
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: -- RSA Digest Extension for Data
|
||||
|
||||
///
|
||||
/// Digest Handling Extension
|
||||
///
|
||||
extension Data {
|
||||
|
||||
// MARK: Enums
|
||||
|
||||
///
|
||||
/// Enumerates available Digest algorithms
|
||||
///
|
||||
public enum Algorithm {
|
||||
|
||||
/// Secure Hash Algorithm 1
|
||||
case sha1
|
||||
|
||||
/// Secure Hash Algorithm 2 224-bit
|
||||
case sha224
|
||||
|
||||
/// Secure Hash Algorithm 2 256-bit
|
||||
case sha256
|
||||
|
||||
/// Secure Hash Algorithm 2 384-bit
|
||||
case sha384
|
||||
|
||||
/// Secure Hash Algorithm 2 512-bit
|
||||
case sha512
|
||||
|
||||
/// Secure Hash Algorithm 1 using AES-GCM envelope encryption.
|
||||
/// use this algorithm for cross platform encryption/decryption.
|
||||
case gcm
|
||||
|
||||
/// Digest Length
|
||||
public var length: CC_LONG {
|
||||
|
||||
#if os(Linux)
|
||||
|
||||
switch self {
|
||||
|
||||
case .sha1:
|
||||
return CC_LONG(SHA_DIGEST_LENGTH)
|
||||
|
||||
case .sha224:
|
||||
return CC_LONG(SHA224_DIGEST_LENGTH)
|
||||
|
||||
case .sha256:
|
||||
return CC_LONG(SHA256_DIGEST_LENGTH)
|
||||
|
||||
case .sha384:
|
||||
return CC_LONG(SHA384_DIGEST_LENGTH)
|
||||
|
||||
case .sha512:
|
||||
return CC_LONG(SHA512_DIGEST_LENGTH)
|
||||
|
||||
case .gcm:
|
||||
return CC_LONG(SHA_DIGEST_LENGTH)
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
switch self {
|
||||
|
||||
case .sha1:
|
||||
return CC_LONG(CC_SHA1_DIGEST_LENGTH)
|
||||
|
||||
case .sha224:
|
||||
return CC_LONG(CC_SHA224_DIGEST_LENGTH)
|
||||
|
||||
case .sha256:
|
||||
return CC_LONG(CC_SHA256_DIGEST_LENGTH)
|
||||
|
||||
case .sha384:
|
||||
return CC_LONG(CC_SHA384_DIGEST_LENGTH)
|
||||
|
||||
case .sha512:
|
||||
return CC_LONG(CC_SHA512_DIGEST_LENGTH)
|
||||
|
||||
case .gcm:
|
||||
return CC_LONG(CC_SHA1_DIGEST_LENGTH)
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#if os(Linux)
|
||||
|
||||
// Hash, padding type
|
||||
public var algorithmForSignature: (OpaquePointer?, Int32) {
|
||||
|
||||
switch self {
|
||||
|
||||
case .sha1:
|
||||
return (.init(EVP_sha1()), RSA_PKCS1_PADDING)
|
||||
|
||||
case .sha224:
|
||||
return (.init(EVP_sha224()), RSA_PKCS1_PADDING)
|
||||
|
||||
case .sha256:
|
||||
return (.init(EVP_sha256()), RSA_PKCS1_PADDING)
|
||||
|
||||
case .sha384:
|
||||
return (.init(EVP_sha384()), RSA_PKCS1_PADDING)
|
||||
|
||||
case .sha512:
|
||||
return (.init(EVP_sha512()), RSA_PKCS1_PADDING)
|
||||
|
||||
case .gcm:
|
||||
return (.init(EVP_sha1()), RSA_PKCS1_PADDING)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// HMAC type, symmetric encryption, padding type
|
||||
public var alogrithmForEncryption: (OpaquePointer?, OpaquePointer?, Int32) {
|
||||
|
||||
switch self {
|
||||
|
||||
case .sha1:
|
||||
return (.init(EVP_sha1()), .init(EVP_aes_256_cbc()), RSA_PKCS1_OAEP_PADDING)
|
||||
|
||||
case .sha224:
|
||||
return (.init(EVP_sha224()), .init(EVP_aes_256_cbc()), RSA_PKCS1_OAEP_PADDING)
|
||||
|
||||
case .sha256:
|
||||
return (.init(EVP_sha256()), .init(EVP_aes_256_cbc()), RSA_PKCS1_OAEP_PADDING)
|
||||
|
||||
case .sha384:
|
||||
return (.init(EVP_sha384()), .init(EVP_aes_256_cbc()), RSA_PKCS1_OAEP_PADDING)
|
||||
|
||||
case .sha512:
|
||||
return (.init(EVP_sha512()), .init(EVP_aes_128_gcm()), RSA_PKCS1_OAEP_PADDING)
|
||||
|
||||
case .gcm:
|
||||
return (.init(EVP_sha1()), .init(EVP_aes_128_gcm()), RSA_PKCS1_OAEP_PADDING)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
@available(macOS 10.12, iOS 10.0, watchOS 3.3, tvOS 12.0, *)
|
||||
public var algorithmForSignature: SecKeyAlgorithm {
|
||||
|
||||
switch self {
|
||||
|
||||
case .sha1:
|
||||
return .rsaSignatureMessagePKCS1v15SHA1
|
||||
|
||||
case .sha224:
|
||||
return .rsaSignatureMessagePKCS1v15SHA224
|
||||
|
||||
case .sha256:
|
||||
return .rsaSignatureMessagePKCS1v15SHA256
|
||||
|
||||
case .sha384:
|
||||
return .rsaSignatureMessagePKCS1v15SHA384
|
||||
|
||||
case .sha512:
|
||||
return .rsaSignatureMessagePKCS1v15SHA512
|
||||
|
||||
case .gcm:
|
||||
return .rsaSignatureMessagePKCS1v15SHA1
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)
|
||||
var algorithmForPssSignature: SecKeyAlgorithm {
|
||||
switch self {
|
||||
|
||||
case .sha1:
|
||||
return .rsaSignatureMessagePSSSHA1
|
||||
|
||||
case .sha224:
|
||||
return .rsaSignatureMessagePSSSHA224
|
||||
|
||||
case .sha256:
|
||||
return .rsaSignatureMessagePSSSHA256
|
||||
|
||||
case .sha384:
|
||||
return .rsaSignatureMessagePSSSHA384
|
||||
|
||||
case .sha512:
|
||||
return .rsaSignatureMessagePSSSHA512
|
||||
|
||||
case .gcm:
|
||||
return .rsaSignatureMessagePSSSHA1
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 10.12, iOS 10.0, watchOS 3.3, tvOS 12.0, *)
|
||||
public var alogrithmForEncryption: SecKeyAlgorithm {
|
||||
|
||||
switch self {
|
||||
|
||||
case .sha1:
|
||||
return .rsaEncryptionOAEPSHA1AESGCM
|
||||
|
||||
case .sha224:
|
||||
return .rsaEncryptionOAEPSHA224AESGCM
|
||||
|
||||
case .sha256:
|
||||
return .rsaEncryptionOAEPSHA256AESGCM
|
||||
|
||||
case .sha384:
|
||||
return .rsaEncryptionOAEPSHA384AESGCM
|
||||
|
||||
case .sha512:
|
||||
return .rsaEncryptionOAEPSHA512AESGCM
|
||||
|
||||
case .gcm:
|
||||
return .rsaEncryptionOAEPSHA1AESGCM
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// The platform/alogorithm dependent function to be used.
|
||||
/// (UnsafePointer<UInt8>!, Int, UnsafeMutablePointer<UInt8>!) -> UnsafeMutablePointer<UInt8>!
|
||||
#if os(Linux)
|
||||
|
||||
public var engine: (_ data: UnsafePointer<UInt8>, _ len: CC_LONG, _ md: UnsafeMutablePointer<UInt8>) -> UnsafeMutablePointer<UInt8>? {
|
||||
|
||||
switch self {
|
||||
|
||||
case .sha1:
|
||||
return SHA1
|
||||
|
||||
case .sha224:
|
||||
return SHA224
|
||||
|
||||
case .sha256:
|
||||
return SHA256
|
||||
|
||||
case .sha384:
|
||||
return SHA384
|
||||
|
||||
case .sha512:
|
||||
return SHA512
|
||||
|
||||
case .gcm:
|
||||
return SHA1
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
public var engine: (_ data: UnsafeRawPointer, _ len: CC_LONG, _ md: UnsafeMutablePointer<UInt8>) -> UnsafeMutablePointer<UInt8>? {
|
||||
|
||||
switch self {
|
||||
|
||||
case .sha1:
|
||||
return CC_SHA1
|
||||
|
||||
case .sha224:
|
||||
return CC_SHA224
|
||||
|
||||
case .sha256:
|
||||
return CC_SHA256
|
||||
|
||||
case .sha384:
|
||||
return CC_SHA384
|
||||
|
||||
case .sha512:
|
||||
return CC_SHA512
|
||||
|
||||
case .gcm:
|
||||
return CC_SHA1
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// MARK: Functions
|
||||
|
||||
///
|
||||
/// Return a digest of the data based on the alogorithm selected.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - alogorithm: The digest `Alogorithm` to use.
|
||||
///
|
||||
/// - Returns: `Data` containing the data in digest form.
|
||||
///
|
||||
public func digest(using alogorithm: Algorithm) throws -> Data {
|
||||
|
||||
var hash = [UInt8](repeating: 0, count: Int(alogorithm.length))
|
||||
|
||||
self.withUnsafeBytes { ptr in
|
||||
guard let baseAddress = ptr.baseAddress else { return }
|
||||
_ = alogorithm.engine(baseAddress.assumingMemoryBound(to: UInt8.self), CC_LONG(self.count), &hash)
|
||||
}
|
||||
|
||||
return Data(hash)
|
||||
}
|
||||
}
|
||||
108
Pods/BlueRSA/Sources/CryptorRSA/CryptorRSAErrors.swift
generated
Normal file
108
Pods/BlueRSA/Sources/CryptorRSA/CryptorRSAErrors.swift
generated
Normal file
@ -0,0 +1,108 @@
|
||||
//
|
||||
// CryptorRSAErrors.swift
|
||||
// CryptorRSA
|
||||
//
|
||||
// Created by Bill Abt on 1/18/17.
|
||||
//
|
||||
// Copyright © 2017 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
|
||||
|
||||
// MARK: -
|
||||
|
||||
@available(macOS 10.12, iOS 10.3, watchOS 3.3, tvOS 12.0, *)
|
||||
extension CryptorRSA {
|
||||
|
||||
// MARK: Constants
|
||||
|
||||
// MARK: -- Generic
|
||||
|
||||
// MARK: -- Errors: Domain and Codes
|
||||
|
||||
public static let ERR_DOMAIN = "com.ibm.oss.CryptorRSA.ErrorDomain"
|
||||
|
||||
public static let ERR_ADD_KEY = -9999
|
||||
public static let ERR_DELETE_KEY = -9998
|
||||
public static let ERR_STRIP_PK_HEADER = -9997
|
||||
public static let ERR_INIT_PK = -9996
|
||||
public static let ERR_BASE64_PEM_DATA = -9995
|
||||
public static let ERR_STRING_ENCODING = -9994
|
||||
public static let ERR_KEY_NOT_PUBLIC = -9993
|
||||
public static let ERR_KEY_NOT_PRIVATE = -9992
|
||||
public static let ERR_NOT_ENCRYPTED = -9991
|
||||
public static let ERR_ENCRYPTION_FAILED = -9990
|
||||
public static let ERR_NOT_SIGNED_DATA = -9989
|
||||
public static let ERR_NOT_PLAINTEXT = -9988
|
||||
public static let ERR_DECRYPTION_FAILED = -9997
|
||||
public static let ERR_SIGNING_FAILED = -9986
|
||||
public static let ERR_VERIFICATION_FAILED = -9985
|
||||
public static let ERR_CREATE_CERT_FAILED = -9984
|
||||
public static let ERR_EXTRACT_PUBLIC_KEY_FAILED = -9983
|
||||
public static let ERR_EXTRACT_PRIVATE_KEY_FAILED = -9983
|
||||
public static let ERR_NOT_IMPLEMENTED = -9982
|
||||
|
||||
// MARK: -- Error
|
||||
|
||||
///
|
||||
/// `RSA` specific error structure.
|
||||
///
|
||||
public struct Error: Swift.Error, CustomStringConvertible {
|
||||
|
||||
// MARK: -- Public Properties
|
||||
|
||||
///
|
||||
/// The error domain.
|
||||
///
|
||||
public let domain: String = ERR_DOMAIN
|
||||
|
||||
///
|
||||
/// The error code: **see constants above for possible errors** (Readonly)
|
||||
///
|
||||
public internal(set) var errorCode: Int32
|
||||
|
||||
///
|
||||
/// The reason for the error **(if available)** (Readonly)
|
||||
///
|
||||
public internal(set) var errorReason: String?
|
||||
|
||||
///
|
||||
/// Returns a string description of the error. (Readonly)
|
||||
///
|
||||
public var description: String {
|
||||
|
||||
let reason: String = self.errorReason ?? "Reason: Unavailable"
|
||||
return "Error code: \(self.errorCode)(0x\(String(self.errorCode, radix: 16, uppercase: true))), \(reason)"
|
||||
}
|
||||
|
||||
// MARK: -- Public Functions
|
||||
|
||||
///
|
||||
/// Initializes an Error Instance
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - code: Error code
|
||||
/// - reason: Optional Error Reason
|
||||
///
|
||||
/// - Returns: Error instance
|
||||
///
|
||||
public init(code: Int, reason: String?) {
|
||||
|
||||
self.errorCode = Int32(code)
|
||||
self.errorReason = reason
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
932
Pods/BlueRSA/Sources/CryptorRSA/CryptorRSAKey.swift
generated
Normal file
932
Pods/BlueRSA/Sources/CryptorRSA/CryptorRSAKey.swift
generated
Normal file
@ -0,0 +1,932 @@
|
||||
//
|
||||
// CryptorRSAKey.swift
|
||||
// CryptorRSA
|
||||
//
|
||||
// Created by Bill Abt on 1/18/17.
|
||||
//
|
||||
// Copyright © 2017 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.
|
||||
//
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
import CommonCrypto
|
||||
#elseif os(Linux)
|
||||
import OpenSSL
|
||||
#endif
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: -
|
||||
|
||||
@available(macOS 10.12, iOS 10.3, watchOS 3.3, tvOS 12.0, *)
|
||||
extension CryptorRSA {
|
||||
|
||||
// MARK: Type Aliases
|
||||
|
||||
#if os(Linux)
|
||||
|
||||
public typealias NativeKey = OpaquePointer?
|
||||
|
||||
#else
|
||||
|
||||
public typealias NativeKey = SecKey
|
||||
|
||||
#endif
|
||||
|
||||
// MARK: Class Functions
|
||||
|
||||
// MARK: -- Public Key Creation
|
||||
|
||||
///
|
||||
/// Creates a public key with DER data.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - data: Key data
|
||||
///
|
||||
/// - Returns: New `PublicKey` instance.
|
||||
///
|
||||
public class func createPublicKey(with data: Data) throws -> PublicKey {
|
||||
|
||||
return try PublicKey(with: data)
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a public key by extracting it from a certificate.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - data: `Data` representing the certificate.
|
||||
///
|
||||
/// - Returns: New `PublicKey` instance.
|
||||
///
|
||||
public class func createPublicKey(extractingFrom data: Data) throws -> PublicKey {
|
||||
|
||||
// Extact the data as a base64 string...
|
||||
let str = String(data: data, encoding: .utf8)
|
||||
guard let tmp = str else {
|
||||
|
||||
throw Error(code: ERR_CREATE_CERT_FAILED, reason: "Unable to create certificate from certificate data, incorrect format.")
|
||||
}
|
||||
|
||||
// Get the Base64 representation of the PEM encoded string after stripping off the PEM markers...
|
||||
let base64 = try CryptorRSA.base64String(for: tmp)
|
||||
let data = Data(base64Encoded: base64)!
|
||||
|
||||
// Call the internal function to finish up...
|
||||
return try CryptorRSA.createPublicKey(data: data)
|
||||
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a key with a base64-encoded string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - base64String: Base64-encoded key data
|
||||
///
|
||||
/// - Returns: New `PublicKey` instance.
|
||||
///
|
||||
public class func createPublicKey(withBase64 base64String: String) throws -> PublicKey {
|
||||
|
||||
guard let data = Data(base64Encoded: base64String, options: [.ignoreUnknownCharacters]) else {
|
||||
|
||||
throw Error(code: ERR_INIT_PK, reason: "Couldn't decode base64 string")
|
||||
}
|
||||
|
||||
return try PublicKey(with: data)
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a key with a PEM string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - pemString: PEM-encoded key string
|
||||
///
|
||||
/// - Returns: New `PublicKey` instance.
|
||||
///
|
||||
public class func createPublicKey(withPEM pemString: String) throws -> PublicKey {
|
||||
|
||||
// Get the Base64 representation of the PEM encoded string after stripping off the PEM markers
|
||||
let base64String = try CryptorRSA.base64String(for: pemString)
|
||||
|
||||
return try createPublicKey(withBase64: base64String)
|
||||
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a key with a PEM file.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - pemName: Name of the PEM file
|
||||
/// - path: Path where the file is located.
|
||||
///
|
||||
/// - Returns: New `PublicKey` instance.
|
||||
///
|
||||
public class func createPublicKey(withPEMNamed pemName: String, onPath path: String) throws -> PublicKey {
|
||||
|
||||
var certName = pemName
|
||||
if !pemName.hasSuffix(PEM_SUFFIX) {
|
||||
|
||||
certName = pemName.appending(PEM_SUFFIX)
|
||||
}
|
||||
|
||||
let fullPath = URL(fileURLWithPath: #file).appendingPathComponent( path.appending(certName) ).standardized
|
||||
|
||||
let keyString = try String(contentsOf: fullPath, encoding: .utf8)
|
||||
|
||||
return try createPublicKey(withPEM: keyString)
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a key with a DER file.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - derName: Name of the DER file
|
||||
/// - path: Path where the file is located.
|
||||
///
|
||||
/// - Returns: New `PublicKey` instance.
|
||||
///
|
||||
public class func createPublicKey(withDERNamed derName: String, onPath path: String) throws -> PublicKey {
|
||||
|
||||
var certName = derName
|
||||
if !derName.hasSuffix(DER_SUFFIX) {
|
||||
|
||||
certName = derName.appending(DER_SUFFIX)
|
||||
}
|
||||
|
||||
let fullPath = URL(fileURLWithPath: #file).appendingPathComponent( path.appending(certName) ).standardized
|
||||
|
||||
let data = try Data(contentsOf: fullPath)
|
||||
|
||||
return try PublicKey(with: data)
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a public key by extracting it from a certificate.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - certName: Name of the certificate file.
|
||||
/// - path: Path where the file is located.
|
||||
///
|
||||
/// - Returns: New `PublicKey` instance.
|
||||
///
|
||||
public class func createPublicKey(extractingFrom certName: String, onPath path: String) throws -> PublicKey {
|
||||
|
||||
var certNameFull = certName
|
||||
if !certName.hasSuffix(CER_SUFFIX) {
|
||||
|
||||
certNameFull = certName.appending(CER_SUFFIX)
|
||||
}
|
||||
|
||||
let fullPath = URL(fileURLWithPath: #file).appendingPathComponent( path.appending(certNameFull) ).standardized
|
||||
|
||||
// Get the Base64 representation of the PEM encoded string after stripping off the PEM markers...
|
||||
let tmp = try String(contentsOf: fullPath, encoding: .utf8)
|
||||
let base64 = try CryptorRSA.base64String(for: tmp)
|
||||
let data = Data(base64Encoded: base64)!
|
||||
|
||||
return try CryptorRSA.createPublicKey(data: data)
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a key with a PEM file.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - pemName: Name of the PEM file
|
||||
/// - bundle: Bundle in which to look for the PEM file. Defaults to the main bundle.
|
||||
///
|
||||
/// - Returns: New `PublicKey` instance.
|
||||
///
|
||||
public class func createPublicKey(withPEMNamed pemName: String, in bundle: Bundle = Bundle.main) throws -> PublicKey {
|
||||
|
||||
guard let path = bundle.path(forResource: pemName, ofType: PEM_SUFFIX) else {
|
||||
|
||||
throw Error(code: ERR_INIT_PK, reason: "Couldn't find a PEM file named '\(pemName)'")
|
||||
}
|
||||
|
||||
let keyString = try String(contentsOf: URL(fileURLWithPath: path), encoding: .utf8)
|
||||
|
||||
return try createPublicKey(withPEM: keyString)
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a key with a DER file.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - derName: Name of the DER file
|
||||
/// - bundle: Bundle in which to look for the DER file. Defaults to the main bundle.
|
||||
///
|
||||
/// - Returns: New `PublicKey` instance.
|
||||
///
|
||||
public class func createPublicKey(withDERNamed derName: String, in bundle: Bundle = Bundle.main) throws -> PublicKey {
|
||||
|
||||
guard let path = bundle.path(forResource: derName, ofType: DER_SUFFIX) else {
|
||||
|
||||
throw Error(code: ERR_INIT_PK, reason: "Couldn't find a DER file named '\(derName)'")
|
||||
}
|
||||
|
||||
let data = try Data(contentsOf: URL(fileURLWithPath: path))
|
||||
|
||||
return try PublicKey(with: data)
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a public key by extracting it from a certificate.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - certName: Name of the certificate file.
|
||||
/// - bundle: Bundle in which to look for the DER file. Defaults to the main bundle.
|
||||
///
|
||||
/// - Returns: New `PublicKey` instance.
|
||||
///
|
||||
public class func createPublicKey(extractingFrom certName: String, in bundle: Bundle = Bundle.main) throws -> PublicKey {
|
||||
|
||||
guard let path = bundle.path(forResource: certName, ofType: CER_SUFFIX) else {
|
||||
|
||||
throw Error(code: ERR_INIT_PK, reason: "Couldn't find a certificate file named '\(certName)'")
|
||||
}
|
||||
|
||||
// Import the data from the file...
|
||||
let tmp = try String(contentsOf: URL(fileURLWithPath: path))
|
||||
let base64 = try CryptorRSA.base64String(for: tmp)
|
||||
let data = Data(base64Encoded: base64)!
|
||||
|
||||
// Call the internal function to finish up...
|
||||
return try CryptorRSA.createPublicKey(data: data)
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a public key by extracting it from certificate data.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - data: `Data` representing the certificate.
|
||||
///
|
||||
/// - Returns: New `PublicKey` instance.
|
||||
///
|
||||
internal class func createPublicKey(data: Data) throws -> PublicKey {
|
||||
|
||||
#if os(Linux)
|
||||
|
||||
let certbio = BIO_new(BIO_s_mem())
|
||||
defer {
|
||||
BIO_free(certbio)
|
||||
}
|
||||
|
||||
// Move the key data to BIO
|
||||
try data.withUnsafeBytes() { (buffer: UnsafeRawBufferPointer) in
|
||||
|
||||
let len = BIO_write(certbio, buffer.baseAddress?.assumingMemoryBound(to: UInt8.self), Int32(data.count))
|
||||
guard len != 0 else {
|
||||
let source = "Couldn't create BIO reference from key data"
|
||||
if let reason = CryptorRSA.getLastError(source: source) {
|
||||
|
||||
throw Error(code: ERR_ADD_KEY, reason: reason)
|
||||
}
|
||||
throw Error(code: ERR_ADD_KEY, reason: source + ": No OpenSSL error reported.")
|
||||
}
|
||||
|
||||
// The below is equivalent of BIO_flush...
|
||||
BIO_ctrl(certbio, BIO_CTRL_FLUSH, 0, nil)
|
||||
}
|
||||
let cert = d2i_X509_bio(certbio, nil)
|
||||
if cert == nil {
|
||||
print("Error loading cert into memory\n")
|
||||
throw Error(code: ERR_CREATE_CERT_FAILED, reason: "Error loading cert into memory.")
|
||||
}
|
||||
|
||||
// Extract the certificate's public key data.
|
||||
let evp_key: OpaquePointer? = .init(X509_get_pubkey(cert))
|
||||
if evp_key == nil {
|
||||
throw Error(code: ERR_CREATE_CERT_FAILED, reason: "Error getting public key from certificate")
|
||||
}
|
||||
|
||||
return PublicKey(with: evp_key)
|
||||
|
||||
#else
|
||||
|
||||
// Create a DER-encoded X.509 certificate object from the DER data...
|
||||
let certificateData = SecCertificateCreateWithData(nil, data as CFData)
|
||||
guard let certData = certificateData else {
|
||||
|
||||
throw Error(code: ERR_CREATE_CERT_FAILED, reason: "Unable to create certificate from certificate data.")
|
||||
}
|
||||
|
||||
var key: SecKey? = nil
|
||||
|
||||
#if swift(>=4.2)
|
||||
#if os(macOS)
|
||||
if #available(macOS 10.14, *) {
|
||||
key = SecCertificateCopyKey(certData)
|
||||
} else {
|
||||
// Now extract the public key from it...
|
||||
let status: OSStatus = withUnsafeMutablePointer(to: &key) { ptr in
|
||||
|
||||
// Retrieves the public key from a certificate...
|
||||
SecCertificateCopyPublicKey(certData, UnsafeMutablePointer(ptr))
|
||||
}
|
||||
|
||||
if status != errSecSuccess {
|
||||
|
||||
throw Error(code: ERR_EXTRACT_PUBLIC_KEY_FAILED, reason: "Unable to extract public key from data.")
|
||||
}
|
||||
}
|
||||
#else
|
||||
let copyKey: (SecCertificate) -> SecKey?
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
copyKey = SecCertificateCopyKey
|
||||
#else
|
||||
if #available(iOS 12.0, watchOS 5.0, *) {
|
||||
copyKey = SecCertificateCopyKey
|
||||
} else {
|
||||
copyKey = SecCertificateCopyPublicKey
|
||||
}
|
||||
#endif
|
||||
|
||||
key = copyKey(certData)
|
||||
#endif
|
||||
#else
|
||||
#if os(macOS)
|
||||
|
||||
// Now extract the public key from it...
|
||||
let status: OSStatus = withUnsafeMutablePointer(to: &key) { ptr in
|
||||
|
||||
// Retrieves the public key from a certificate...
|
||||
SecCertificateCopyPublicKey(certData, UnsafeMutablePointer(ptr))
|
||||
}
|
||||
|
||||
if status != errSecSuccess {
|
||||
|
||||
throw Error(code: ERR_EXTRACT_PUBLIC_KEY_FAILED, reason: "Unable to extract public key from data.")
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
key = SecCertificateCopyPublicKey(certData)
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
guard let createdKey = key else {
|
||||
|
||||
throw Error(code: ERR_EXTRACT_PUBLIC_KEY_FAILED, reason: "Unable to extract public key from data.")
|
||||
}
|
||||
|
||||
return PublicKey(with: createdKey)
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// MARK: -- Private Key Creation
|
||||
|
||||
///
|
||||
/// Creates a private key with data.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - data: Key data
|
||||
///
|
||||
/// - Returns: New `PrivateKey` instance.
|
||||
///
|
||||
public class func createPrivateKey(with data: Data) throws -> PrivateKey {
|
||||
|
||||
return try PrivateKey(with: data)
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a key with a base64-encoded string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - base64String: Base64-encoded key data
|
||||
///
|
||||
/// - Returns: New `PrivateKey` instance.
|
||||
///
|
||||
public class func createPrivateKey(withBase64 base64String: String) throws -> PrivateKey {
|
||||
|
||||
guard let data = Data(base64Encoded: base64String, options: [.ignoreUnknownCharacters]) else {
|
||||
|
||||
throw Error(code: ERR_INIT_PK, reason: "Couldn't decode base 64 string")
|
||||
}
|
||||
|
||||
return try PrivateKey(with: data)
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a key with a PEM string.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - pemString: PEM-encoded key string
|
||||
///
|
||||
/// - Returns: New `PrivateKey` instance.
|
||||
///
|
||||
public class func createPrivateKey(withPEM pemString: String) throws -> PrivateKey {
|
||||
|
||||
let base64String = try CryptorRSA.base64String(for: pemString)
|
||||
|
||||
return try CryptorRSA.createPrivateKey(withBase64: base64String)
|
||||
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a key with a PEM file.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - pemName: Name of the PEM file
|
||||
/// - path: Path where the file is located.
|
||||
///
|
||||
/// - Returns: New `PrivateKey` instance.
|
||||
///
|
||||
public class func createPrivateKey(withPEMNamed pemName: String, onPath path: String) throws -> PrivateKey {
|
||||
|
||||
var certName = pemName
|
||||
if !pemName.hasSuffix(PEM_SUFFIX) {
|
||||
|
||||
certName = pemName.appending(PEM_SUFFIX)
|
||||
}
|
||||
let fullPath = URL(fileURLWithPath: #file).appendingPathComponent( path.appending(certName) ).standardized
|
||||
|
||||
let keyString = try String(contentsOf: fullPath, encoding: .utf8)
|
||||
|
||||
return try CryptorRSA.createPrivateKey(withPEM: keyString)
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a key with a DER file.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - derName: Name of the DER file
|
||||
/// - path: Path where the file is located.
|
||||
///
|
||||
/// - Returns: New `PrivateKey` instance.
|
||||
///
|
||||
public class func createPrivateKey(withDERNamed derName: String, onPath path: String) throws -> PrivateKey {
|
||||
|
||||
var certName = derName
|
||||
if !derName.hasSuffix(DER_SUFFIX) {
|
||||
|
||||
certName = derName.appending(DER_SUFFIX)
|
||||
}
|
||||
let fullPath = URL(fileURLWithPath: #file).appendingPathComponent( path.appending(certName) ).standardized
|
||||
|
||||
let data = try Data(contentsOf: fullPath)
|
||||
|
||||
return try PrivateKey(with: data)
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a key with a PEM file.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - pemName: Name of the PEM file
|
||||
/// - bundle: Bundle in which to look for the PEM file. Defaults to the main bundle.
|
||||
///
|
||||
/// - Returns: New `PrivateKey` instance.
|
||||
///
|
||||
public class func createPrivateKey(withPEMNamed pemName: String, in bundle: Bundle = Bundle.main) throws -> PrivateKey {
|
||||
|
||||
guard let path = bundle.path(forResource: pemName, ofType: PEM_SUFFIX) else {
|
||||
|
||||
throw Error(code: ERR_INIT_PK, reason: "Couldn't find a PEM file named '\(pemName)'")
|
||||
}
|
||||
|
||||
let keyString = try String(contentsOf: URL(fileURLWithPath: path), encoding: .utf8)
|
||||
|
||||
return try CryptorRSA.createPrivateKey(withPEM: keyString)
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a key with a DER file.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - derName: Name of the DER file
|
||||
/// - bundle: Bundle in which to look for the DER file. Defaults to the main bundle.
|
||||
///
|
||||
/// - Returns: New `PrivateKey` instance.
|
||||
///
|
||||
public class func createPrivateKey(withDERNamed derName: String, in bundle: Bundle = Bundle.main) throws -> PrivateKey {
|
||||
|
||||
guard let path = bundle.path(forResource: derName, ofType: DER_SUFFIX) else {
|
||||
|
||||
throw Error(code: ERR_INIT_PK, reason: "Couldn't find a DER file named '\(derName)'")
|
||||
}
|
||||
|
||||
let data = try Data(contentsOf: URL(fileURLWithPath: path))
|
||||
|
||||
return try PrivateKey(with: data)
|
||||
}
|
||||
|
||||
/// Create a new RSA public/private key pair.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - keySize: The size of the generated RSA keys in bits.
|
||||
///
|
||||
/// - Returns: A tuple containing the (`PrivateKey`, `PublicKey`) instances.
|
||||
///
|
||||
public class func makeKeyPair(_ keySize: RSAKey.KeySize) throws -> (PrivateKey, PublicKey) {
|
||||
|
||||
#if os(Linux)
|
||||
var pkey = EVP_PKEY_new()
|
||||
let ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nil)
|
||||
defer {
|
||||
EVP_PKEY_CTX_free(ctx)
|
||||
}
|
||||
guard EVP_PKEY_keygen_init(ctx) == 1,
|
||||
EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_RSA_KEYGEN_BITS, Int32(keySize.bits), nil) == 1,
|
||||
EVP_PKEY_keygen(ctx, &pkey) == 1
|
||||
else {
|
||||
EVP_PKEY_free(pkey)
|
||||
throw Error(code: ERR_INIT_PK, reason: "Could not generate rsa pair for \(keySize.bits) bits")
|
||||
}
|
||||
let privKey = PrivateKey(with: .make(optional: pkey))
|
||||
let publicPem = try RSAKey.getPEMString(reference: privKey.reference, keyType: .publicType, stripped: false)
|
||||
let pubKey = try CryptorRSA.createPublicKey(withPEM: publicPem)
|
||||
|
||||
return(privKey, pubKey)
|
||||
|
||||
#else
|
||||
|
||||
let parameters: [String: AnyObject] = [
|
||||
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
|
||||
kSecAttrKeySizeInBits as String: keySize.bits as AnyObject,
|
||||
kSecPublicKeyAttrs as String: [ kSecAttrIsPermanent as String: true as AnyObject ] as AnyObject,
|
||||
kSecPrivateKeyAttrs as String: [ kSecAttrIsPermanent as String: true as AnyObject ] as AnyObject,
|
||||
]
|
||||
var pubKey, privKey: SecKey?
|
||||
let status = SecKeyGeneratePair(parameters as CFDictionary, &pubKey, &privKey)
|
||||
guard status == 0, let newPubKey = pubKey, let newPrivKey = privKey else {
|
||||
throw Error(code: ERR_INIT_PK, reason: "Could not generate rsa pair for \(keySize.bits) bits")
|
||||
}
|
||||
let privateKey = PrivateKey(with: newPrivKey)
|
||||
let publicKey = PublicKey(with: newPubKey)
|
||||
|
||||
return (privateKey, publicKey)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// MARK: -
|
||||
|
||||
///
|
||||
/// RSA Key Creation and Handling
|
||||
///
|
||||
public class RSAKey {
|
||||
|
||||
// MARK: Enums
|
||||
|
||||
/// Denotes the type of key this represents.
|
||||
public enum KeyType {
|
||||
|
||||
/// Public
|
||||
case publicType
|
||||
|
||||
/// Private
|
||||
case privateType
|
||||
}
|
||||
|
||||
/// Denotes the size of the RSA key.
|
||||
public struct KeySize {
|
||||
let bits: Int
|
||||
/// A 1024 bit RSA key. Not recommended since this may become breakable in the near future.
|
||||
public static let bits1024 = KeySize(bits: 1024)
|
||||
/// A 2048 bit RSA key. Recommended if security will not be required beyond 2030.
|
||||
public static let bits2048 = KeySize(bits: 2048)
|
||||
/// A 3072 bit RSA key. Recommended if security is required beyond 2030.
|
||||
public static let bits3072 = KeySize(bits: 3072)
|
||||
/// A 4096 bit RSA key.
|
||||
public static let bits4096 = KeySize(bits: 4096)
|
||||
}
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// The RSA key as a PKCS#1 PEM String
|
||||
public let pemString: String
|
||||
|
||||
/// The stored key
|
||||
internal let reference: NativeKey
|
||||
|
||||
#if os(Linux)
|
||||
var publicKeyBytes: Data?
|
||||
deinit {
|
||||
EVP_PKEY_free(.make(optional: reference))
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Represents the type of key data contained.
|
||||
public internal(set) var type: KeyType = .publicType
|
||||
|
||||
// MARK: Initializers
|
||||
|
||||
///
|
||||
/// Create a key using key data (in DER format).
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - data: Key data.
|
||||
/// - type: Type of key data.
|
||||
///
|
||||
/// - Returns: New `RSAKey` instance.
|
||||
///
|
||||
internal init(with data: Data, type: KeyType) throws {
|
||||
|
||||
var data = data
|
||||
|
||||
// If data is a PEM String, strip the headers and convert to der.
|
||||
if let pemString = String(data: data, encoding: .utf8),
|
||||
let base64String = try? CryptorRSA.base64String(for: pemString),
|
||||
let base64Data = Data(base64Encoded: base64String) {
|
||||
data = base64Data
|
||||
}
|
||||
data = try CryptorRSA.stripX509CertificateHeader(for: data)
|
||||
self.pemString = CryptorRSA.convertDerToPem(from: data, type: type)
|
||||
self.type = type
|
||||
reference = try CryptorRSA.createKey(from: data, type: type)
|
||||
#if os(Linux)
|
||||
if let pubString = try? RSAKey.getPEMString(reference: reference, keyType: .publicType, stripped: true),
|
||||
let base64String = try? CryptorRSA.base64String(for: pubString),
|
||||
let derData = Data(base64Encoded: base64String) {
|
||||
self.publicKeyBytes = derData
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
///
|
||||
/// Create a key using a native key.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - nativeKey: Native key representation.
|
||||
/// - type: Type of key.
|
||||
///
|
||||
/// - Returns: New `RSAKey` instance.
|
||||
///
|
||||
internal init(with nativeKey: NativeKey, type: KeyType) {
|
||||
|
||||
self.type = type
|
||||
self.reference = nativeKey
|
||||
self.pemString = (try? RSAKey.getPEMString(reference: nativeKey, type: type)) ?? ""
|
||||
#if os(Linux)
|
||||
if let base64String = try? CryptorRSA.base64String(for: pemString),
|
||||
let derData = Data(base64Encoded: base64String) {
|
||||
self.publicKeyBytes = derData
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if os(Linux) && !swift(>=4.1)
|
||||
|
||||
///
|
||||
/// Create a key using a native key.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - nativeKey: Pointer to RSA key structure.
|
||||
/// - type: Type of key.
|
||||
///
|
||||
/// - Returns: New `RSAKey` instance.
|
||||
///
|
||||
internal init(with nativeKey: UnsafeMutablePointer<EVP_PKEY>, type: KeyType) {
|
||||
|
||||
self.type = type
|
||||
self.reference = .make(optional: nativeKey)
|
||||
self.pemString = (try? RSAKey.getPEMString(reference: .init(nativeKey), type: type)) ?? ""
|
||||
if let base64String = try? CryptorRSA.base64String(for: pemString),
|
||||
let derData = Data(base64Encoded: base64String) {
|
||||
self.publicKeyBytes = derData
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
///
|
||||
/// Get the RSA key as a PEM String.
|
||||
///
|
||||
/// - Returns: The RSA Key in PEM format.
|
||||
///
|
||||
static func getPEMString(reference: NativeKey, type: KeyType) throws -> String {
|
||||
|
||||
#if os(Linux)
|
||||
return try getPEMString(reference: reference, keyType: type, stripped: true)
|
||||
#else
|
||||
var error: Unmanaged<CFError>? = nil
|
||||
guard let keyBytes = SecKeyCopyExternalRepresentation(reference, &error) else {
|
||||
guard let error = error?.takeRetainedValue() else {
|
||||
throw Error(code: ERR_INIT_PK, reason: "Couldn't read PEM String")
|
||||
}
|
||||
throw error
|
||||
}
|
||||
return CryptorRSA.convertDerToPem(from: keyBytes as Data, type: type)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if os(Linux)
|
||||
///
|
||||
/// Get a PEM string of a native key.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - reference: Native key.
|
||||
/// - keyType: Type of key.
|
||||
/// - stripped: `true` to return string stripped, `false` otherwise.
|
||||
///
|
||||
/// - Returns: The PEM string.
|
||||
///
|
||||
static func getPEMString(reference: NativeKey, keyType: KeyType, stripped: Bool) throws -> String {
|
||||
let asn1Bio = BIO_new(BIO_s_mem())
|
||||
defer { BIO_free_all(asn1Bio) }
|
||||
if keyType == .publicType {
|
||||
PEM_write_bio_PUBKEY(asn1Bio, .make(optional: reference))
|
||||
} else {
|
||||
PEM_write_bio_PrivateKey(asn1Bio, .make(optional: reference), nil, nil, 0, nil, nil)
|
||||
}
|
||||
// 4096 bit rsa PEM key is 3272 bytes of data
|
||||
let asn1 = UnsafeMutablePointer<UInt8>.allocate(capacity: 3500)
|
||||
let readLength = BIO_read(asn1Bio, asn1, 3500)
|
||||
let pemData = Data(bytes: asn1, count: Int(readLength))
|
||||
#if swift(>=4.1)
|
||||
asn1.deallocate()
|
||||
#else
|
||||
asn1.deallocate(capacity: 3500)
|
||||
#endif
|
||||
guard let pemString = String(data: pemData, encoding: .utf8) else {
|
||||
throw Error(code: ERR_INIT_PK, reason: "Couldn't utf8 decode pemString")
|
||||
}
|
||||
if !stripped {
|
||||
return pemString
|
||||
} else {
|
||||
let derString = try CryptorRSA.base64String(for: pemString)
|
||||
guard let derData = Data(base64Encoded: derString) else {
|
||||
throw Error(code: ERR_INIT_PK, reason: "Couldn't read PEM String")
|
||||
}
|
||||
let strippedDer = try CryptorRSA.stripX509CertificateHeader(for: derData)
|
||||
let pkcs1PEM = CryptorRSA.convertDerToPem(from: strippedDer, type: keyType)
|
||||
return pkcs1PEM
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// MARK: -
|
||||
|
||||
///
|
||||
/// Public Key - Represents public key data.
|
||||
///
|
||||
public class PublicKey: RSAKey {
|
||||
|
||||
/// MARK: Statics
|
||||
|
||||
/// Regular expression for the PK using the begin and end markers.
|
||||
static let publicKeyRegex: NSRegularExpression? = {
|
||||
|
||||
let publicKeyRegex = "(\(CryptorRSA.PK_BEGIN_MARKER).+?\(CryptorRSA.PK_END_MARKER))"
|
||||
return try? NSRegularExpression(pattern: publicKeyRegex, options: .dotMatchesLineSeparators)
|
||||
}()
|
||||
|
||||
// MARK: -- Static Functions
|
||||
|
||||
///
|
||||
/// Takes an input string, scans for public key sections, and then returns a Key for any valid keys found
|
||||
/// - This method scans the file for public key armor - if no keys are found, an empty array is returned
|
||||
/// - Each public key block found is "parsed" by `publicKeyFromPEMString()`
|
||||
/// - should that method throw, the error is _swallowed_ and not rethrown
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - pemString: The string to use to parse out values
|
||||
///
|
||||
/// - Returns: An array of `PublicKey` objects containing just public keys.
|
||||
///
|
||||
public static func publicKeys(withPEM pemString: String) -> [PublicKey] {
|
||||
|
||||
// If our regexp isn't valid, or the input string is empty, we can't move forward…
|
||||
guard let publicKeyRegexp = publicKeyRegex, pemString.count > 0 else {
|
||||
return []
|
||||
}
|
||||
|
||||
let all = NSRange(
|
||||
location: 0,
|
||||
length: pemString.count
|
||||
)
|
||||
|
||||
let matches = publicKeyRegexp.matches(
|
||||
in: pemString,
|
||||
options: NSRegularExpression.MatchingOptions(rawValue: 0),
|
||||
range: all
|
||||
)
|
||||
|
||||
#if swift(>=4.1)
|
||||
|
||||
let keys = matches.compactMap { result -> PublicKey? in
|
||||
|
||||
let match = result.range(at: 1)
|
||||
let start = pemString.index(pemString.startIndex, offsetBy: match.location)
|
||||
let end = pemString.index(start, offsetBy: match.length)
|
||||
|
||||
let range = start..<end
|
||||
|
||||
let thisKey = pemString[range]
|
||||
|
||||
return try? CryptorRSA.createPublicKey(withPEM: String(thisKey))
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
let keys = matches.flatMap { result -> PublicKey? in
|
||||
|
||||
let match = result.range(at: 1)
|
||||
let start = pemString.index(pemString.startIndex, offsetBy: match.location)
|
||||
let end = pemString.index(start, offsetBy: match.length)
|
||||
|
||||
let range = start..<end
|
||||
|
||||
let thisKey = pemString[range]
|
||||
|
||||
return try? CryptorRSA.createPublicKey(withPEM: String(thisKey))
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
// MARK: -- Initializers
|
||||
|
||||
///
|
||||
/// Create a public key using key data.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - data: Key data
|
||||
///
|
||||
/// - Returns: New `PublicKey` instance.
|
||||
///
|
||||
public init(with data: Data) throws {
|
||||
try super.init(with: data, type: .publicType)
|
||||
}
|
||||
|
||||
///
|
||||
/// Create a key using a native key.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - nativeKey: Native key representation.
|
||||
///
|
||||
/// - Returns: New `PublicKey` instance.
|
||||
///
|
||||
public init(with nativeKey: NativeKey) {
|
||||
|
||||
super.init(with: nativeKey, type: .publicType)
|
||||
}
|
||||
|
||||
#if os(Linux) && !swift(>=4.1)
|
||||
|
||||
///
|
||||
/// Create a key using a native key.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - nativeKey: Pointer to RSA key structure.
|
||||
///
|
||||
/// - Returns: New `RSAKey` instance.
|
||||
///
|
||||
public init(with nativeKey: UnsafeMutablePointer<EVP_PKEY>) {
|
||||
|
||||
super.init(with: nativeKey, type: .publicType)
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
///
|
||||
/// Private Key - Represents private key data.
|
||||
///
|
||||
public class PrivateKey: RSAKey {
|
||||
|
||||
// MARK: -- Initializers
|
||||
|
||||
///
|
||||
/// Create a private key using key data.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - data: Key data
|
||||
///
|
||||
/// - Returns: New `PrivateKey` instance.
|
||||
///
|
||||
public init(with data: Data) throws {
|
||||
try super.init(with: data, type: .privateType)
|
||||
}
|
||||
|
||||
///
|
||||
/// Create a key using a native key.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - nativeKey: Native key representation.
|
||||
///
|
||||
/// - Returns: New `PrivateKey` instance.
|
||||
///
|
||||
public init(with nativeKey: NativeKey) {
|
||||
|
||||
super.init(with: nativeKey, type: .privateType)
|
||||
}
|
||||
}
|
||||
}
|
||||
393
Pods/BlueRSA/Sources/CryptorRSA/CryptorRSAUtilities.swift
generated
Normal file
393
Pods/BlueRSA/Sources/CryptorRSA/CryptorRSAUtilities.swift
generated
Normal file
@ -0,0 +1,393 @@
|
||||
//
|
||||
// Utilities.swift
|
||||
// CryptorRSA
|
||||
//
|
||||
// Created by Bill Abt on 1/17/17.
|
||||
//
|
||||
// Copyright © 2017 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.
|
||||
//
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
import CommonCrypto
|
||||
#elseif os(Linux)
|
||||
import OpenSSL
|
||||
#endif
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: -- RSAUtilities
|
||||
|
||||
///
|
||||
/// Various RSA Related Utility Functions
|
||||
///
|
||||
@available(macOS 10.12, iOS 10.3, watchOS 3.3, tvOS 12.0, *)
|
||||
public extension CryptorRSA {
|
||||
|
||||
#if os(Linux)
|
||||
|
||||
///
|
||||
/// Create a key from key data.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - keyData: `Data` representation of the key.
|
||||
/// - type: Type of key data.
|
||||
///
|
||||
/// - Returns: `RSA` representation of the key.
|
||||
///
|
||||
static func createKey(from keyData: Data, type: CryptorRSA.RSAKey.KeyType) throws -> NativeKey {
|
||||
|
||||
var keyData = keyData
|
||||
|
||||
// If data is a PEM String, strip the headers and convert to der.
|
||||
if let pemString = String(data: keyData, encoding: .utf8),
|
||||
let base64String = try? CryptorRSA.base64String(for: pemString),
|
||||
let base64Data = Data(base64Encoded: base64String) {
|
||||
keyData = base64Data
|
||||
}
|
||||
|
||||
let headerKey = CryptorRSA.addX509CertificateHeader(for: keyData)
|
||||
|
||||
// Create a memory BIO...
|
||||
let bio = BIO_new(BIO_s_mem())
|
||||
|
||||
defer {
|
||||
BIO_free(bio)
|
||||
}
|
||||
// Create a BIO object with the key data...
|
||||
try headerKey.withUnsafeBytes() { (buffer: UnsafeRawBufferPointer) in
|
||||
|
||||
let len = BIO_write(bio, buffer.baseAddress?.assumingMemoryBound(to: UInt8.self), Int32(headerKey.count))
|
||||
guard len != 0 else {
|
||||
let source = "Couldn't create BIO reference from key data"
|
||||
if let reason = CryptorRSA.getLastError(source: source) {
|
||||
|
||||
throw Error(code: ERR_ADD_KEY, reason: reason)
|
||||
}
|
||||
throw Error(code: ERR_ADD_KEY, reason: source + ": No OpenSSL error reported.")
|
||||
}
|
||||
// The below is equivalent of BIO_flush...
|
||||
BIO_ctrl(bio, BIO_CTRL_FLUSH, 0, nil)
|
||||
}
|
||||
|
||||
var evp_key: OpaquePointer?
|
||||
|
||||
// Read in the key data and process depending on key type...
|
||||
if type == .publicType {
|
||||
|
||||
evp_key = .init(d2i_PUBKEY_bio(bio, nil))
|
||||
|
||||
} else {
|
||||
|
||||
evp_key = .init(d2i_PrivateKey_bio(bio, nil))
|
||||
}
|
||||
return evp_key
|
||||
}
|
||||
|
||||
///
|
||||
/// Retrieve the OpenSSL error and text.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - source: The string describing the error.
|
||||
///
|
||||
/// - Returns: `String` containing the error or `nil` if no error found.
|
||||
///
|
||||
static func getLastError(source: String) -> String? {
|
||||
|
||||
var errorString: String
|
||||
|
||||
let errorCode = Int32(ERR_get_error())
|
||||
|
||||
if errorCode == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if let errorStr = ERR_reason_error_string(UInt(errorCode)) {
|
||||
errorString = String(validatingUTF8: errorStr)!
|
||||
} else {
|
||||
errorString = "Could not determine error reason."
|
||||
}
|
||||
|
||||
let reason = "ERROR: \(source), code: \(errorCode), reason: \(errorString)"
|
||||
return reason
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
///
|
||||
/// Create a key from key data.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - keyData: `Data` representation of the key.
|
||||
/// - type: Type of key data.
|
||||
///
|
||||
/// - Returns: `SecKey` representation of the key.
|
||||
///
|
||||
static func createKey(from keyData: Data, type: CryptorRSA.RSAKey.KeyType) throws -> NativeKey {
|
||||
|
||||
let keyClass = type == .publicType ? kSecAttrKeyClassPublic : kSecAttrKeyClassPrivate
|
||||
|
||||
let sizeInBits = keyData.count * MemoryLayout<UInt8>.size
|
||||
let keyDict: [CFString: Any] = [
|
||||
kSecAttrKeyType: kSecAttrKeyTypeRSA,
|
||||
kSecAttrKeyClass: keyClass,
|
||||
kSecAttrKeySizeInBits: NSNumber(value: sizeInBits)
|
||||
]
|
||||
|
||||
guard let key = SecKeyCreateWithData(keyData as CFData, keyDict as CFDictionary, nil) else {
|
||||
|
||||
throw Error(code: ERR_ADD_KEY, reason: "Couldn't create key reference from key data")
|
||||
}
|
||||
|
||||
return key
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
///
|
||||
/// Convert DER data to PEM data.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - derData: `Data` in DER format.
|
||||
/// - type: Type of key data.
|
||||
///
|
||||
/// - Returns: PEM `Data` representation.
|
||||
///
|
||||
static func convertDerToPem(from derData: Data, type: CryptorRSA.RSAKey.KeyType) -> String {
|
||||
|
||||
// First convert the DER data to a base64 string...
|
||||
let base64String = derData.base64EncodedString()
|
||||
|
||||
// Split the string into strings of length 65...
|
||||
let lines = base64String.split(to: 65)
|
||||
|
||||
// Join those lines with a new line...
|
||||
let joinedLines = lines.joined(separator: "\n")
|
||||
|
||||
// Add the appropriate header and footer depending on whether the key is public or private...
|
||||
if type == .publicType {
|
||||
|
||||
return ("-----BEGIN RSA PUBLIC KEY-----\n" + joinedLines + "\n-----END RSA PUBLIC KEY-----")
|
||||
|
||||
} else {
|
||||
|
||||
return (CryptorRSA.SK_BEGIN_MARKER + "\n" + joinedLines + "\n" + CryptorRSA.SK_END_MARKER)
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Get the Base64 representation of a PEM encoded string after stripping off the PEM markers.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - pemString: `String` containing PEM formatted data.
|
||||
///
|
||||
/// - Returns: Base64 encoded `String` containing the data.
|
||||
///
|
||||
static func base64String(for pemString: String) throws -> String {
|
||||
|
||||
// Filter looking for new lines...
|
||||
var lines = pemString.components(separatedBy: "\n").filter { line in
|
||||
return !line.hasPrefix(CryptorRSA.GENERIC_BEGIN_MARKER) && !line.hasPrefix(CryptorRSA.GENERIC_END_MARKER)
|
||||
}
|
||||
|
||||
// No lines, no data...
|
||||
guard lines.count != 0 else {
|
||||
throw Error(code: ERR_BASE64_PEM_DATA, reason: "Couldn't get data from PEM key: no data available after stripping headers.")
|
||||
}
|
||||
|
||||
// Strip off any carriage returns...
|
||||
lines = lines.map { $0.replacingOccurrences(of: "\r", with: "") }
|
||||
|
||||
return lines.joined(separator: "")
|
||||
}
|
||||
|
||||
///
|
||||
/// This function strips the x509 from a provided ASN.1 DER public key. If the key doesn't contain a header,
|
||||
/// the DER data is returned as is.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - keyData: `Data` containing the public key with or without the x509 header.
|
||||
///
|
||||
/// - Returns: `Data` containing the public with header (if present) removed.
|
||||
///
|
||||
static func stripX509CertificateHeader(for keyData: Data) throws -> Data {
|
||||
|
||||
// If private key in pkcs8 format, strip the header
|
||||
if keyData[26] == 0x30 {
|
||||
return(keyData.advanced(by: 26))
|
||||
}
|
||||
|
||||
let count = keyData.count / MemoryLayout<CUnsignedChar>.size
|
||||
|
||||
guard count > 0 else {
|
||||
|
||||
throw Error(code: ERR_STRIP_PK_HEADER, reason: "Provided public key is empty")
|
||||
}
|
||||
|
||||
let byteArray = [UInt8](keyData)
|
||||
|
||||
var index = 0
|
||||
guard byteArray[index] == 0x30 else {
|
||||
|
||||
throw Error(code: ERR_STRIP_PK_HEADER, reason: "Provided key doesn't have a valid ASN.1 structure (first byte should be 0x30 == SEQUENCE)")
|
||||
}
|
||||
|
||||
index += 1
|
||||
if byteArray[index] > 0x80 {
|
||||
index += Int(byteArray[index]) - 0x80 + 1
|
||||
} else {
|
||||
index += 1
|
||||
}
|
||||
|
||||
// If current byte marks an integer (0x02), it means the key doesn't have a X509 header and just
|
||||
// contains its modulo & public exponent. In this case, we can just return the provided DER data as is.
|
||||
if Int(byteArray[index]) == 0x02 {
|
||||
return keyData
|
||||
}
|
||||
|
||||
// Now that we've excluded the possibility of headerless key, we're looking for a valid X509 header sequence.
|
||||
// It should look like this:
|
||||
// 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00
|
||||
guard Int(byteArray[index]) == 0x30 else {
|
||||
|
||||
throw Error(code: ERR_STRIP_PK_HEADER, reason: "Provided key doesn't have a valid X509 header")
|
||||
}
|
||||
|
||||
index += 15
|
||||
if byteArray[index] != 0x03 {
|
||||
|
||||
throw Error(code: ERR_STRIP_PK_HEADER, reason: "Invalid byte at index \(index - 1) (\(byteArray[index - 1])) for public key header")
|
||||
}
|
||||
|
||||
index += 1
|
||||
if byteArray[index] > 0x80 {
|
||||
index += Int(byteArray[index]) - 0x80 + 1
|
||||
} else {
|
||||
index += 1
|
||||
}
|
||||
|
||||
guard byteArray[index] == 0 else {
|
||||
|
||||
throw Error(code: ERR_STRIP_PK_HEADER, reason: "Invalid byte at index \(index - 1) (\(byteArray[index - 1])) for public key header")
|
||||
}
|
||||
|
||||
index += 1
|
||||
|
||||
let strippedKeyBytes = [UInt8](byteArray[index...keyData.count - 1])
|
||||
let data = Data(bytes: UnsafePointer<UInt8>(strippedKeyBytes), count: keyData.count - index)
|
||||
return data
|
||||
}
|
||||
|
||||
///
|
||||
/// Add an X509 certificate header to key data.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - keyData: Data to add the header to.
|
||||
///
|
||||
/// - Returns: The modified key data.
|
||||
///
|
||||
static func addX509CertificateHeader(for keyData: Data) -> Data {
|
||||
|
||||
if keyData.count == 140 {
|
||||
return Data([0x30, 0x81, 0x9F,
|
||||
0x30, 0x0D,
|
||||
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
|
||||
0x05, 0x00,
|
||||
0x03, 0x81, 0x8D, 0x00]) + keyData
|
||||
} else if keyData.count == 270 {
|
||||
return Data([0x30, 0x82, 0x01, 0x22,
|
||||
0x30, 0x0D,
|
||||
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
|
||||
0x05, 0x00,
|
||||
0x03, 0x82, 0x01, 0x0F, 0x00]) + keyData
|
||||
} else if keyData.count == 398 {
|
||||
return Data([0x30, 0x82, 0x01, 0xA2,
|
||||
0x30, 0x0D,
|
||||
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
|
||||
0x05, 0x00,
|
||||
0x03, 0x82, 0x01, 0x8F, 0x00]) + keyData
|
||||
} else if keyData.count == 526 {
|
||||
return Data([0x30, 0x82, 0x02, 0x22,
|
||||
0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
|
||||
0x05, 0x00,
|
||||
0x03, 0x82, 0x02, 0x0F, 0x00]) + keyData
|
||||
} else {
|
||||
return keyData
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension String {
|
||||
|
||||
///
|
||||
/// Split a string to a specified length.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - length: Length of each split string.
|
||||
///
|
||||
/// - Returns: `[String]` containing each string.
|
||||
///
|
||||
func split(to length: Int) -> [String] {
|
||||
|
||||
var result = [String]()
|
||||
var collectedCharacters = [Character]()
|
||||
collectedCharacters.reserveCapacity(length)
|
||||
var count = 0
|
||||
|
||||
for character in self {
|
||||
collectedCharacters.append(character)
|
||||
count += 1
|
||||
if count == length {
|
||||
// Reached the desired length
|
||||
count = 0
|
||||
result.append(String(collectedCharacters))
|
||||
collectedCharacters.removeAll(keepingCapacity: true)
|
||||
}
|
||||
}
|
||||
|
||||
// Append the remainder
|
||||
if !collectedCharacters.isEmpty {
|
||||
result.append(String(collectedCharacters))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: -
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
// MARK: -- CFString Extension for Hashing
|
||||
|
||||
///
|
||||
/// Extension to CFString to make it hashable.
|
||||
///
|
||||
extension CFString: Hashable {
|
||||
|
||||
/// Return the hash value of a CFString
|
||||
public var hashValue: Int {
|
||||
return (self as String).hashValue
|
||||
}
|
||||
|
||||
/// Comparison of CFStrings
|
||||
static public func == (lhs: CFString, rhs: CFString) -> Bool {
|
||||
return lhs as String == rhs as String
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
38
Pods/BlueRSA/Sources/CryptorRSA/Data+Extensions.swift
generated
Normal file
38
Pods/BlueRSA/Sources/CryptorRSA/Data+Extensions.swift
generated
Normal file
@ -0,0 +1,38 @@
|
||||
// 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
|
||||
100
Pods/BlueRSA/Sources/CryptorRSA/SSLPointerTricks.swift
generated
Normal file
100
Pods/BlueRSA/Sources/CryptorRSA/SSLPointerTricks.swift
generated
Normal file
@ -0,0 +1,100 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is taken from SwiftNIO open source project
|
||||
//
|
||||
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// MARK:- Awful code begins here
|
||||
// Hello dear reader. Let me explain what we're doing here.
|
||||
//
|
||||
// From OpenSSL 1.0 to OpenSSL 1.1 one of the major breaking changes was the so-called
|
||||
// "great opaquifiying". Essentially, OpenSSL took all of its public structures and made
|
||||
// them opaque, such that they cannot be introspected from client code. This is a great
|
||||
// forward step, and brings them more in line with modern C library practices.
|
||||
//
|
||||
// However, it's an *enormous* inconvenience from Swift code. This is because the Swift
|
||||
// translation of the C type `SSL_CTX *` changed from `UnsafeMutablePointer<SSL_CTX>` to
|
||||
// `OpaquePointer`.
|
||||
//
|
||||
// This change exists for reasonable enough reasons in Swift land (see
|
||||
// https://forums.swift.org/t/opaque-pointers-in-swift/6875 for a discussion), but
|
||||
// nonetheless causes enormous problems in our codebase.
|
||||
//
|
||||
// Our cheap way out is to make everything an OpaquePointer, and then provide initializers
|
||||
// between OpaquePointer and the typed pointers. This allows us to tolerate either pointer
|
||||
// type in our Swift code by bridging them over to OpaquePointer and back, and lets the
|
||||
// compiler worry about how exactly to make that work.
|
||||
//
|
||||
// Now, in fact, Swift already has initializers between the pointer types. What it does
|
||||
// not have is self-initializers: the ability to create an `OpaquePointer` from an `OpaquePointer`,
|
||||
// or an `UnsafePointer<T>` from an `UnsafePointer<T>`. We add those two initializers here.
|
||||
// We also add a special "make" function that exists to handle the special case of optional pointer
|
||||
// values, which we mostly encounter in the ALPN callbacks.
|
||||
//
|
||||
// The *downside* of this approach is that we totally break the pointer type system. It becomes
|
||||
// trivially possible to alias a pointer of type T to type U through two calls to init. This
|
||||
// is not a thing we want to widely promote. For this reason, these extensions are hidden in
|
||||
// this file, where we can laugh and jeer at them and generally make them feel bad about
|
||||
// themselves.
|
||||
//
|
||||
// Hopefully, in time, these extensions can be removed.
|
||||
|
||||
extension UnsafePointer {
|
||||
init(_ ptr: UnsafePointer<Pointee>) {
|
||||
self = ptr
|
||||
}
|
||||
|
||||
static func make(optional ptr: UnsafePointer<Pointee>?) -> UnsafePointer<Pointee>? {
|
||||
return ptr.map(UnsafePointer<Pointee>.init)
|
||||
}
|
||||
|
||||
static func make(optional ptr: OpaquePointer?) -> UnsafePointer<Pointee>? {
|
||||
return ptr.map(UnsafePointer<Pointee>.init)
|
||||
}
|
||||
}
|
||||
|
||||
extension UnsafeMutablePointer {
|
||||
init(_ ptr: UnsafeMutableRawPointer) {
|
||||
let x = UnsafeMutablePointer<Pointee>(bitPattern: UInt(bitPattern: ptr))!
|
||||
self = x
|
||||
}
|
||||
|
||||
static func make(optional ptr: UnsafeMutablePointer<Pointee>?) -> UnsafeMutablePointer<Pointee>? {
|
||||
return ptr.map(UnsafeMutablePointer<Pointee>.init)
|
||||
}
|
||||
|
||||
static func make(optional ptr: UnsafeMutableRawPointer?) -> UnsafeMutablePointer<Pointee>? {
|
||||
return ptr.map(UnsafeMutablePointer<Pointee>.init)
|
||||
}
|
||||
|
||||
static func make(optional ptr: OpaquePointer?) -> UnsafeMutablePointer<Pointee>? {
|
||||
return ptr.map(UnsafeMutablePointer<Pointee>.init)
|
||||
}
|
||||
}
|
||||
|
||||
extension UnsafeMutableRawPointer {
|
||||
static func make(optional ptr: OpaquePointer?) -> UnsafeMutableRawPointer? {
|
||||
return ptr.map(UnsafeMutableRawPointer.init)
|
||||
}
|
||||
}
|
||||
|
||||
extension OpaquePointer {
|
||||
init(_ ptr: OpaquePointer) {
|
||||
self = ptr
|
||||
}
|
||||
|
||||
static func make(optional ptr: OpaquePointer?) -> OpaquePointer? {
|
||||
return ptr.map(OpaquePointer.init)
|
||||
}
|
||||
|
||||
static func make(optional ptr: UnsafeMutableRawPointer?) -> OpaquePointer? {
|
||||
return ptr.map(OpaquePointer.init)
|
||||
}
|
||||
|
||||
static func make<Pointee>(optional ptr: UnsafeMutablePointer<Pointee>?) -> OpaquePointer? {
|
||||
return ptr.map(OpaquePointer.init)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user