更新了登录

This commit is contained in:
DDIsFriend
2023-10-08 16:18:31 +08:00
parent 257a974426
commit 000bf8eccf
48 changed files with 10122 additions and 7665 deletions

220
Pods/SwiftyRSA/Source/Asn1Parser.swift generated Normal file
View File

@@ -0,0 +1,220 @@
//
// Asn1Parser.swift
// SwiftyRSA
//
// Created by Lois Di Qual on 5/9/17.
// Copyright © 2017 Scoop. All rights reserved.
//
import Foundation
/// Simple data scanner that consumes bytes from a raw data and keeps an updated position.
private class Scanner {
enum ScannerError: Error {
case outOfBounds
}
let data: Data
var index: Int = 0
/// Returns whether there is no more data to consume
var isComplete: Bool {
return index >= data.count
}
/// Creates a scanner with provided data
///
/// - Parameter data: Data to consume
init(data: Data) {
self.data = data
}
/// Consumes data of provided length and returns it
///
/// - Parameter length: length of the data to consume
/// - Returns: data consumed
/// - Throws: ScannerError.outOfBounds error if asked to consume too many bytes
func consume(length: Int) throws -> Data {
guard length > 0 else {
return Data()
}
guard index + length <= data.count else {
throw ScannerError.outOfBounds
}
let subdata = data.subdata(in: index..<index + length)
index += length
return subdata
}
/// Consumes a primitive, definite ASN1 length and returns its value.
///
/// See http://luca.ntop.org/Teaching/Appunti/asn1.html,
///
/// - Short form. One octet. Bit 8 has value "0" and bits 7-1 give the length.
/// - Long form. Two to 127 octets. Bit 8 of first octet has value "1" and
/// bits 7-1 give the number of additional length octets.
/// Second and following octets give the length, base 256, most significant digit first.
///
/// - Returns: Length that was consumed
/// - Throws: ScannerError.outOfBounds error if asked to consume too many bytes
func consumeLength() throws -> Int {
let lengthByte = try consume(length: 1).firstByte
// If the first byte's value is less than 0x80, it directly contains the length
// so we can return it
guard lengthByte >= 0x80 else {
return Int(lengthByte)
}
// If the first byte's value is more than 0x80, it indicates how many following bytes
// will describe the length. For instance, 0x85 indicates that 0x85 - 0x80 = 0x05 = 5
// bytes will describe the length, so we need to read the 5 next bytes and get their integer
// value to determine the length.
let nextByteCount = lengthByte - 0x80
let length = try consume(length: Int(nextByteCount))
return length.integer
}
}
private extension Data {
/// Returns the first byte of the current data
var firstByte: UInt8 {
var byte: UInt8 = 0
copyBytes(to: &byte, count: MemoryLayout<UInt8>.size)
return byte
}
/// Returns the integer value of the current data.
/// @warning: this only supports data up to 4 bytes, as we can only extract 32-bit integers.
var integer: Int {
guard count > 0 else {
return 0
}
var int: UInt32 = 0
var offset: Int32 = Int32(count - 1)
forEach { byte in
let byte32 = UInt32(byte)
let shifted = byte32 << (UInt32(offset) * 8)
int = int | shifted
offset -= 1
}
return Int(int)
}
}
/// A simple ASN1 parser that will recursively iterate over a root node and return a Node tree.
/// The root node can be any of the supported nodes described in `Node`. If the parser encounters a sequence
/// it will recursively parse its children.
enum Asn1Parser {
/// An ASN1 node
enum Node {
case sequence(nodes: [Node])
case integer(data: Data)
case objectIdentifier(data: Data)
case null
case bitString(data: Data)
case octetString(data: Data)
}
enum ParserError: Error {
case noType
case invalidType(value: UInt8)
}
/// Parses ASN1 data and returns its root node.
///
/// - Parameter data: ASN1 data to parse
/// - Returns: Root ASN1 Node
/// - Throws: A ParserError if anything goes wrong, or if an unknown node was encountered
static func parse(data: Data) throws -> Node {
let scanner = Scanner(data: data)
let node = try parseNode(scanner: scanner)
return node
}
/// Parses an ASN1 given an existing scanne.
/// @warning: this will modify the state (ie: position) of the provided scanner.
///
/// - Parameter scanner: Scanner to use to consume the data
/// - Returns: Parsed node
/// - Throws: A ParserError if anything goes wrong, or if an unknown node was encountered
private static func parseNode(scanner: Scanner) throws -> Node {
let firstByte = try scanner.consume(length: 1).firstByte
// Sequence
if firstByte == 0x30 {
let length = try scanner.consumeLength()
let data = try scanner.consume(length: length)
let nodes = try parseSequence(data: data)
return .sequence(nodes: nodes)
}
// Integer
if firstByte == 0x02 {
let length = try scanner.consumeLength()
let data = try scanner.consume(length: length)
return .integer(data: data)
}
// Object identifier
if firstByte == 0x06 {
let length = try scanner.consumeLength()
let data = try scanner.consume(length: length)
return .objectIdentifier(data: data)
}
// Null
if firstByte == 0x05 {
_ = try scanner.consume(length: 1)
return .null
}
// Bit String
if firstByte == 0x03 {
let length = try scanner.consumeLength()
// There's an extra byte (0x00) after the bit string length in all the keys I've encountered.
// I couldn't find a specification that referenced this extra byte, but let's consume it and discard it.
_ = try scanner.consume(length: 1)
let data = try scanner.consume(length: length - 1)
return .bitString(data: data)
}
// Octet String
if firstByte == 0x04 {
let length = try scanner.consumeLength()
let data = try scanner.consume(length: length)
return .octetString(data: data)
}
throw ParserError.invalidType(value: firstByte)
}
/// Parses an ASN1 sequence and returns its child nodes
///
/// - Parameter data: ASN1 data
/// - Returns: A list of ASN1 nodes
/// - Throws: A ParserError if anything goes wrong, or if an unknown node was encountered
private static func parseSequence(data: Data) throws -> [Node] {
let scanner = Scanner(data: data)
var nodes: [Node] = []
while !scanner.isComplete {
let node = try parseNode(scanner: scanner)
nodes.append(node)
}
return nodes
}
}

180
Pods/SwiftyRSA/Source/ClearMessage.swift generated Normal file
View File

@@ -0,0 +1,180 @@
//
// ClearMessage.swift
// SwiftyRSA
//
// Created by Lois Di Qual on 5/18/17.
// Copyright © 2017 Scoop. All rights reserved.
//
import Foundation
public class ClearMessage: Message {
/// Data of the message
public let data: Data
/// Creates a clear message with data.
///
/// - Parameter data: Data of the clear message
public required init(data: Data) {
self.data = data
}
/// Creates a clear message from a string, with the specified encoding.
///
/// - Parameters:
/// - string: String value of the clear message
/// - encoding: Encoding to use to generate the clear data
/// - Throws: SwiftyRSAError
public convenience init(string: String, using encoding: String.Encoding) throws {
guard let data = string.data(using: encoding) else {
throw SwiftyRSAError.stringToDataConversionFailed
}
self.init(data: data)
}
/// Returns the string representation of the clear message using the specified
/// string encoding.
///
/// - Parameter encoding: Encoding to use during the string conversion
/// - Returns: String representation of the clear message
/// - Throws: SwiftyRSAError
public func string(encoding: String.Encoding) throws -> String {
guard let str = String(data: data, encoding: encoding) else {
throw SwiftyRSAError.dataToStringConversionFailed
}
return str
}
/// Encrypts a clear message with a public key and returns an encrypted message.
///
/// - Parameters:
/// - key: Public key to encrypt the clear message with
/// - padding: Padding to use during the encryption
/// - Returns: Encrypted message
/// - Throws: SwiftyRSAError
public func encrypted(with key: PublicKey, padding: Padding) throws -> EncryptedMessage {
let blockSize = SecKeyGetBlockSize(key.reference)
var maxChunkSize: Int
switch padding {
case []:
maxChunkSize = blockSize
case .OAEP:
maxChunkSize = blockSize - 42
default:
maxChunkSize = blockSize - 11
}
var decryptedDataAsArray = [UInt8](repeating: 0, count: data.count)
(data as NSData).getBytes(&decryptedDataAsArray, length: data.count)
var encryptedDataBytes = [UInt8](repeating: 0, count: 0)
var idx = 0
while idx < decryptedDataAsArray.count {
let idxEnd = min(idx + maxChunkSize, decryptedDataAsArray.count)
let chunkData = [UInt8](decryptedDataAsArray[idx..<idxEnd])
var encryptedDataBuffer = [UInt8](repeating: 0, count: blockSize)
var encryptedDataLength = blockSize
let status = SecKeyEncrypt(key.reference, padding, chunkData, chunkData.count, &encryptedDataBuffer, &encryptedDataLength)
guard status == noErr else {
throw SwiftyRSAError.chunkEncryptFailed(index: idx)
}
encryptedDataBytes += encryptedDataBuffer
idx += maxChunkSize
}
let encryptedData = Data(bytes: encryptedDataBytes, count: encryptedDataBytes.count)
return EncryptedMessage(data: encryptedData)
}
/// Signs a clear message using a private key.
/// The clear message will first be hashed using the specified digest type, then signed
/// using the provided private key.
///
/// - Parameters:
/// - key: Private key to sign the clear message with
/// - digestType: Digest
/// - Returns: Signature of the clear message after signing it with the specified digest type.
/// - Throws: SwiftyRSAError
public func signed(with key: PrivateKey, digestType: Signature.DigestType) throws -> Signature {
let digest = self.digest(digestType: digestType)
let blockSize = SecKeyGetBlockSize(key.reference)
let maxChunkSize = blockSize - 11
guard digest.count <= maxChunkSize else {
throw SwiftyRSAError.invalidDigestSize(digestSize: digest.count, maxChunkSize: maxChunkSize)
}
var digestBytes = [UInt8](repeating: 0, count: digest.count)
(digest as NSData).getBytes(&digestBytes, length: digest.count)
var signatureBytes = [UInt8](repeating: 0, count: blockSize)
var signatureDataLength = blockSize
let status = SecKeyRawSign(key.reference, digestType.padding, digestBytes, digestBytes.count, &signatureBytes, &signatureDataLength)
guard status == noErr else {
throw SwiftyRSAError.signatureCreateFailed(status: status)
}
let signatureData = Data(bytes: signatureBytes, count: signatureBytes.count)
return Signature(data: signatureData)
}
/// Verifies the signature of a clear message.
///
/// - Parameters:
/// - key: Public key to verify the signature with
/// - signature: Signature to verify
/// - digestType: Digest type used for the signature
/// - Returns: Result of the verification
/// - Throws: SwiftyRSAError
public func verify(with key: PublicKey, signature: Signature, digestType: Signature.DigestType) throws -> Bool {
let digest = self.digest(digestType: digestType)
var digestBytes = [UInt8](repeating: 0, count: digest.count)
(digest as NSData).getBytes(&digestBytes, length: digest.count)
var signatureBytes = [UInt8](repeating: 0, count: signature.data.count)
(signature.data as NSData).getBytes(&signatureBytes, length: signature.data.count)
let status = SecKeyRawVerify(key.reference, digestType.padding, digestBytes, digestBytes.count, signatureBytes, signatureBytes.count)
if status == errSecSuccess {
return true
} else if status == -9809 {
return false
} else {
throw SwiftyRSAError.signatureVerifyFailed(status: status)
}
}
func digest(digestType: Signature.DigestType) -> Data {
let digest: Data
switch digestType {
case .sha1:
digest = (data as NSData).swiftyRSASHA1()
case .sha224:
digest = (data as NSData).swiftyRSASHA224()
case .sha256:
digest = (data as NSData).swiftyRSASHA256()
case .sha384:
digest = (data as NSData).swiftyRSASHA384()
case .sha512:
digest = (data as NSData).swiftyRSASHA512()
}
return digest
}
}

View File

@@ -0,0 +1,59 @@
//
// EncryptedMessage.swift
// SwiftyRSA
//
// Created by Lois Di Qual on 5/18/17.
// Copyright © 2017 Scoop. All rights reserved.
//
import Foundation
public class EncryptedMessage: Message {
/// Data of the message
public let data: Data
/// Creates an encrypted message with data.
///
/// - Parameter data: Data of the encrypted message.
public required init(data: Data) {
self.data = data
}
/// Decrypts an encrypted message with a private key and returns a clear message.
///
/// - Parameters:
/// - key: Private key to decrypt the mssage with
/// - padding: Padding to use during the decryption
/// - Returns: Clear message
/// - Throws: SwiftyRSAError
public func decrypted(with key: PrivateKey, padding: Padding) throws -> ClearMessage {
let blockSize = SecKeyGetBlockSize(key.reference)
var encryptedDataAsArray = [UInt8](repeating: 0, count: data.count)
(data as NSData).getBytes(&encryptedDataAsArray, length: data.count)
var decryptedDataBytes = [UInt8](repeating: 0, count: 0)
var idx = 0
while idx < encryptedDataAsArray.count {
let idxEnd = min(idx + blockSize, encryptedDataAsArray.count)
let chunkData = [UInt8](encryptedDataAsArray[idx..<idxEnd])
var decryptedDataBuffer = [UInt8](repeating: 0, count: blockSize)
var decryptedDataLength = blockSize
let status = SecKeyDecrypt(key.reference, padding, chunkData, idxEnd-idx, &decryptedDataBuffer, &decryptedDataLength)
guard status == noErr else {
throw SwiftyRSAError.chunkDecryptFailed(index: idx)
}
decryptedDataBytes += [UInt8](decryptedDataBuffer[0..<decryptedDataLength])
idx += blockSize
}
let decryptedData = Data(bytes: decryptedDataBytes, count: decryptedDataBytes.count)
return ClearMessage(data: decryptedData)
}
}

90
Pods/SwiftyRSA/Source/Key.swift generated Normal file
View File

@@ -0,0 +1,90 @@
//
// Key.swift
// SwiftyRSA
//
// Created by Loïs Di Qual on 9/19/16.
// Copyright © 2016 Scoop. All rights reserved.
//
import Foundation
import Security
public protocol Key: AnyObject {
var reference: SecKey { get }
var originalData: Data? { get }
init(data: Data) throws
init(reference: SecKey) throws
init(base64Encoded base64String: String) throws
init(pemEncoded pemString: String) throws
init(pemNamed pemName: String, in bundle: Bundle) throws
init(derNamed derName: String, in bundle: Bundle) throws
func pemString() throws -> String
func data() throws -> Data
func base64String() throws -> String
}
public extension Key {
/// Returns a Base64 representation of the public key.
///
/// - Returns: Data of the key, Base64-encoded
/// - Throws: SwiftyRSAError
func base64String() throws -> String {
return try data().base64EncodedString()
}
func data() throws -> Data {
return try SwiftyRSA.data(forKeyReference: reference)
}
/// Creates a public key with a base64-encoded string.
///
/// - Parameter base64String: Base64-encoded public key data
/// - Throws: SwiftyRSAError
init(base64Encoded base64String: String) throws {
guard let data = Data(base64Encoded: base64String, options: [.ignoreUnknownCharacters]) else {
throw SwiftyRSAError.invalidBase64String
}
try self.init(data: data)
}
/// Creates a public key with a PEM string.
///
/// - Parameter pemString: PEM-encoded public key string
/// - Throws: SwiftyRSAError
init(pemEncoded pemString: String) throws {
let base64String = try SwiftyRSA.base64String(pemEncoded: pemString)
try self.init(base64Encoded: base64String)
}
/// Creates a public 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.
/// - Throws: SwiftyRSAError
init(pemNamed pemName: String, in bundle: Bundle = Bundle.main) throws {
guard let path = bundle.path(forResource: pemName, ofType: "pem") else {
throw SwiftyRSAError.pemFileNotFound(name: pemName)
}
let keyString = try String(contentsOf: URL(fileURLWithPath: path), encoding: .utf8)
try self.init(pemEncoded: keyString)
}
/// Creates a private 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.
/// - Throws: SwiftyRSAError
init(derNamed derName: String, in bundle: Bundle = Bundle.main) throws {
guard let path = bundle.path(forResource: derName, ofType: "der") else {
throw SwiftyRSAError.derFileNotFound(name: derName)
}
let data = try Data(contentsOf: URL(fileURLWithPath: path))
try self.init(data: data)
}
}

35
Pods/SwiftyRSA/Source/Message.swift generated Normal file
View File

@@ -0,0 +1,35 @@
//
// Message.swift
// SwiftyRSA
//
// Created by Loïs Di Qual on 9/19/16.
// Copyright © 2016 Scoop. All rights reserved.
//
import Foundation
public protocol Message {
var data: Data { get }
var base64String: String { get }
init(data: Data)
init(base64Encoded base64String: String) throws
}
public extension Message {
/// Base64-encoded string of the message data
var base64String: String {
return data.base64EncodedString()
}
/// Creates an encrypted message with a base64-encoded string.
///
/// - Parameter base64String: Base64-encoded data of the encrypted message
/// - Throws: SwiftyRSAError
init(base64Encoded base64String: String) throws {
guard let data = Data(base64Encoded: base64String) else {
throw SwiftyRSAError.invalidBase64String
}
self.init(data: data)
}
}

19
Pods/SwiftyRSA/Source/NSData+SHA.h generated Normal file
View File

@@ -0,0 +1,19 @@
//
// NSData_SHA1.h
// SwiftyRSA
//
// Created by Paul Wilkinson on 19/04/2016.
// Copyright © 2016 Scoop. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSData (NSData_SwiftyRSASHA)
- (nonnull NSData*) SwiftyRSASHA1;
- (nonnull NSData*) SwiftyRSASHA224;
- (nonnull NSData*) SwiftyRSASHA256;
- (nonnull NSData*) SwiftyRSASHA384;
- (nonnull NSData*) SwiftyRSASHA512;
@end

54
Pods/SwiftyRSA/Source/NSData+SHA.m generated Normal file
View File

@@ -0,0 +1,54 @@
//
// NSData_SHA1.h
// SwiftyRSA
//
// Created by Paul Wilkinson on 19/04/2016.
// Copyright © 2016 Scoop. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCrypto.h>
@implementation NSData (NSData_SwiftyRSASHA)
- (nonnull NSData*) SwiftyRSASHA1 {
unsigned int outputLength = CC_SHA1_DIGEST_LENGTH;
unsigned char output[outputLength];
CC_SHA1(self.bytes, (unsigned int) self.length, output);
return [NSData dataWithBytes:output length:outputLength];
}
- (nonnull NSData*) SwiftyRSASHA224 {
unsigned int outputLength = CC_SHA224_DIGEST_LENGTH;
unsigned char output[outputLength];
CC_SHA224(self.bytes, (unsigned int) self.length, output);
return [NSData dataWithBytes:output length:outputLength];
}
- (nonnull NSData*) SwiftyRSASHA256 {
unsigned int outputLength = CC_SHA256_DIGEST_LENGTH;
unsigned char output[outputLength];
CC_SHA256(self.bytes, (unsigned int) self.length, output);
return [NSData dataWithBytes:output length:outputLength];
}
- (nonnull NSData*) SwiftyRSASHA384 {
unsigned int outputLength = CC_SHA384_DIGEST_LENGTH;
unsigned char output[outputLength];
CC_SHA384(self.bytes, (unsigned int) self.length, output);
return [NSData dataWithBytes:output length:outputLength];
}
- (nonnull NSData*) SwiftyRSASHA512 {
unsigned int outputLength = CC_SHA512_DIGEST_LENGTH;
unsigned char output[outputLength];
CC_SHA512(self.bytes, (unsigned int) self.length, output);
return [NSData dataWithBytes:output length:outputLength];
}
@end

65
Pods/SwiftyRSA/Source/PrivateKey.swift generated Normal file
View File

@@ -0,0 +1,65 @@
//
// PrivateKey.swift
// SwiftyRSA
//
// Created by Lois Di Qual on 5/17/17.
// Copyright © 2017 Scoop. All rights reserved.
//
import Foundation
public class PrivateKey: Key {
/// Reference to the key within the keychain
public let reference: SecKey
/// Original data of the private key.
/// Note that it does not contain PEM headers and holds data as bytes, not as a base 64 string.
public let originalData: Data?
let tag: String?
/// Returns a PEM representation of the private key.
///
/// - Returns: Data of the key, PEM-encoded
/// - Throws: SwiftyRSAError
public func pemString() throws -> String {
let data = try self.data()
let pem = SwiftyRSA.format(keyData: data, withPemType: "RSA PRIVATE KEY")
return pem
}
/// Creates a private key with a keychain key reference.
/// This initializer will throw if the provided key reference is not a private RSA key.
///
/// - Parameter reference: Reference to the key within the keychain.
/// - Throws: SwiftyRSAError
public required init(reference: SecKey) throws {
guard SwiftyRSA.isValidKeyReference(reference, forClass: kSecAttrKeyClassPrivate) else {
throw SwiftyRSAError.notAPrivateKey
}
self.reference = reference
self.tag = nil
self.originalData = nil
}
/// Creates a private key with a RSA public key data.
///
/// - Parameter data: Private key data
/// - Throws: SwiftyRSAError
required public init(data: Data) throws {
self.originalData = data
let tag = UUID().uuidString
self.tag = tag
let dataWithoutHeader = try SwiftyRSA.stripKeyHeader(keyData: data)
reference = try SwiftyRSA.addKey(dataWithoutHeader, isPublic: false, tag: tag)
}
deinit {
if let tag = tag {
SwiftyRSA.removeKey(tag: tag)
}
}
}

116
Pods/SwiftyRSA/Source/PublicKey.swift generated Normal file
View File

@@ -0,0 +1,116 @@
//
// PublicKey.swift
// SwiftyRSA
//
// Created by Lois Di Qual on 5/17/17.
// Copyright © 2017 Scoop. All rights reserved.
//
import Foundation
public class PublicKey: Key {
/// Reference to the key within the keychain
public let reference: SecKey
/// Data of the public key as provided when creating the key.
/// Note that if the key was created from a base64string / DER string / PEM file / DER file,
/// the data holds the actual bytes of the key, not any textual representation like PEM headers
/// or base64 characters.
public let originalData: Data?
let tag: String? // Only used on iOS 8/9
/// Returns a PEM representation of the public key.
///
/// - Returns: Data of the key, PEM-encoded
/// - Throws: SwiftyRSAError
public func pemString() throws -> String {
let data = try self.data()
let pem = SwiftyRSA.format(keyData: data, withPemType: "RSA PUBLIC KEY")
return pem
}
/// Creates a public key with a keychain key reference.
/// This initializer will throw if the provided key reference is not a public RSA key.
///
/// - Parameter reference: Reference to the key within the keychain.
/// - Throws: SwiftyRSAError
public required init(reference: SecKey) throws {
guard SwiftyRSA.isValidKeyReference(reference, forClass: kSecAttrKeyClassPublic) else {
throw SwiftyRSAError.notAPublicKey
}
self.reference = reference
self.tag = nil
self.originalData = nil
}
/// Data of the public key as returned by the keychain.
/// This method throws if SwiftyRSA cannot extract data from the key.
///
/// - Returns: Data of the public key as returned by the keychain.
/// - Throws: SwiftyRSAError
required public init(data: Data) throws {
let tag = UUID().uuidString
self.tag = tag
self.originalData = data
let dataWithoutHeader = try SwiftyRSA.stripKeyHeader(keyData: data)
reference = try SwiftyRSA.addKey(dataWithoutHeader, isPublic: true, tag: tag)
}
static let publicKeyRegex: NSRegularExpression? = {
let publicKeyRegex = "(-----BEGIN PUBLIC KEY-----.+?-----END PUBLIC KEY-----)"
return try? NSRegularExpression(pattern: publicKeyRegex, options: .dotMatchesLineSeparators)
}()
/// Takes an input string, scans for public key sections, and then returns a PublicKey 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
///
/// - parameter pemString: The string to use to parse out values
///
/// - returns: An array of `PublicKey` objects
public static func publicKeys(pemEncoded 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
)
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 thisKey = pemString[start..<end]
return try? PublicKey(pemEncoded: String(thisKey))
}
return keys
}
deinit {
if let tag = tag {
SwiftyRSA.removeKey(tag: tag)
}
}
}

56
Pods/SwiftyRSA/Source/Signature.swift generated Normal file
View File

@@ -0,0 +1,56 @@
//
// Signature.swift
// SwiftyRSA
//
// Created by Loïs Di Qual on 9/19/16.
// Copyright © 2016 Scoop. All rights reserved.
//
import Foundation
public class Signature {
public enum DigestType {
case sha1
case sha224
case sha256
case sha384
case sha512
var padding: Padding {
switch self {
case .sha1: return .PKCS1SHA1
case .sha224: return .PKCS1SHA224
case .sha256: return .PKCS1SHA256
case .sha384: return .PKCS1SHA384
case .sha512: return .PKCS1SHA512
}
}
}
/// Data of the signature
public let data: Data
/// Creates a signature with data.
///
/// - Parameter data: Data of the signature
public init(data: Data) {
self.data = data
}
/// Creates a signature with a base64-encoded string.
///
/// - Parameter base64String: Base64-encoded representation of the signature data.
/// - Throws: SwiftyRSAError
public convenience init(base64Encoded base64String: String) throws {
guard let data = Data(base64Encoded: base64String) else {
throw SwiftyRSAError.invalidBase64String
}
self.init(data: data)
}
/// Returns the base64 representation of the signature.
public var base64String: String {
return data.base64EncodedString()
}
}

280
Pods/SwiftyRSA/Source/SwiftyRSA+ObjC.swift generated Normal file
View File

@@ -0,0 +1,280 @@
//
// SwiftyRSA+ObjC.swift
// SwiftyRSA
//
// Created by Lois Di Qual on 3/6/17.
// Copyright © 2017 Scoop. All rights reserved.
//
import Foundation
/// This files allows the ObjC runtime to access SwiftyRSA classes while keeping the swift code Swiftyish.
/// Things like protocol extensions or throwing and returning booleans are not well supported by ObjC, so instead
/// of giving access to the Swift classes directly, we're wrapping then their `_objc_*` counterpart.
/// They are exposed under the same name to the ObjC runtime, and all methods are present they're just delegated
/// to the wrapped swift value.
private protocol ObjcBridgeable {
associatedtype SwiftType
var swiftValue: SwiftType { get }
init(swiftValue: SwiftType)
}
// MARK: - PublicKey
@objc(PublicKey)
public class _objc_PublicKey: NSObject, Key, ObjcBridgeable { // swiftlint:disable:this type_name
fileprivate let swiftValue: PublicKey
@objc public var reference: SecKey {
return swiftValue.reference
}
@objc public var originalData: Data? {
return swiftValue.originalData
}
@objc public func pemString() throws -> String {
return try swiftValue.pemString()
}
@objc public func data() throws -> Data {
return try swiftValue.data()
}
@objc public func base64String() throws -> String {
return try swiftValue.base64String()
}
required public init(swiftValue: PublicKey) {
self.swiftValue = swiftValue
}
@objc required public init(data: Data) throws {
self.swiftValue = try PublicKey(data: data)
}
@objc public required init(reference: SecKey) throws {
self.swiftValue = try PublicKey(reference: reference)
}
@objc public required init(base64Encoded base64String: String) throws {
self.swiftValue = try PublicKey(base64Encoded: base64String)
}
@objc public required init(pemEncoded pemString: String) throws {
self.swiftValue = try PublicKey(pemEncoded: pemString)
}
@objc public required init(pemNamed pemName: String, in bundle: Bundle) throws {
self.swiftValue = try PublicKey(pemNamed: pemName, in: bundle)
}
@objc public required init(derNamed derName: String, in bundle: Bundle) throws {
self.swiftValue = try PublicKey(derNamed: derName, in: bundle)
}
@objc public static func publicKeys(pemEncoded pemString: String) -> [_objc_PublicKey] {
return PublicKey.publicKeys(pemEncoded: pemString).map { _objc_PublicKey(swiftValue: $0) }
}
}
// MARK: - PrivateKey
@objc(PrivateKey)
public class _objc_PrivateKey: NSObject, Key, ObjcBridgeable { // swiftlint:disable:this type_name
fileprivate let swiftValue: PrivateKey
@objc public var reference: SecKey {
return swiftValue.reference
}
@objc public var originalData: Data? {
return swiftValue.originalData
}
@objc public func pemString() throws -> String {
return try swiftValue.pemString()
}
@objc public func data() throws -> Data {
return try swiftValue.data()
}
@objc public func base64String() throws -> String {
return try swiftValue.base64String()
}
public required init(swiftValue: PrivateKey) {
self.swiftValue = swiftValue
}
@objc public required init(data: Data) throws {
self.swiftValue = try PrivateKey(data: data)
}
@objc public required init(reference: SecKey) throws {
self.swiftValue = try PrivateKey(reference: reference)
}
@objc public required init(base64Encoded base64String: String) throws {
self.swiftValue = try PrivateKey(base64Encoded: base64String)
}
@objc public required init(pemEncoded pemString: String) throws {
self.swiftValue = try PrivateKey(pemEncoded: pemString)
}
@objc public required init(pemNamed pemName: String, in bundle: Bundle) throws {
self.swiftValue = try PrivateKey(pemNamed: pemName, in: bundle)
}
@objc public required init(derNamed derName: String, in bundle: Bundle) throws {
self.swiftValue = try PrivateKey(derNamed: derName, in: bundle)
}
}
// MARK: - VerificationResult
@objc(VerificationResult)
public class _objc_VerificationResult: NSObject { // swiftlint:disable:this type_name
@objc public let isSuccessful: Bool
init(isSuccessful: Bool) {
self.isSuccessful = isSuccessful
}
}
// MARK: - ClearMessage
@objc(ClearMessage)
public class _objc_ClearMessage: NSObject, Message, ObjcBridgeable { // swiftlint:disable:this type_name
fileprivate let swiftValue: ClearMessage
@objc public var base64String: String {
return swiftValue.base64String
}
@objc public var data: Data {
return swiftValue.data
}
public required init(swiftValue: ClearMessage) {
self.swiftValue = swiftValue
}
@objc public required init(data: Data) {
self.swiftValue = ClearMessage(data: data)
}
@objc public required init(string: String, using rawEncoding: UInt) throws {
let encoding = String.Encoding(rawValue: rawEncoding)
self.swiftValue = try ClearMessage(string: string, using: encoding)
}
@objc public required init(base64Encoded base64String: String) throws {
self.swiftValue = try ClearMessage(base64Encoded: base64String)
}
@objc public func string(encoding rawEncoding: UInt) throws -> String {
let encoding = String.Encoding(rawValue: rawEncoding)
return try swiftValue.string(encoding: encoding)
}
@objc public func encrypted(with key: _objc_PublicKey, padding: Padding) throws -> _objc_EncryptedMessage {
let encryptedMessage = try swiftValue.encrypted(with: key.swiftValue, padding: padding)
return _objc_EncryptedMessage(swiftValue: encryptedMessage)
}
@objc public func signed(with key: _objc_PrivateKey, digestType: _objc_Signature.DigestType) throws -> _objc_Signature {
let signature = try swiftValue.signed(with: key.swiftValue, digestType: digestType.swiftValue)
return _objc_Signature(swiftValue: signature)
}
@objc public func verify(with key: _objc_PublicKey, signature: _objc_Signature, digestType: _objc_Signature.DigestType) throws -> _objc_VerificationResult {
let isSuccessful = try swiftValue.verify(with: key.swiftValue, signature: signature.swiftValue, digestType: digestType.swiftValue)
return _objc_VerificationResult(isSuccessful: isSuccessful)
}
}
// MARK: - EncryptedMessage
@objc(EncryptedMessage)
public class _objc_EncryptedMessage: NSObject, Message, ObjcBridgeable { // swiftlint:disable:this type_name
fileprivate let swiftValue: EncryptedMessage
@objc public var base64String: String {
return swiftValue.base64String
}
@objc public var data: Data {
return swiftValue.data
}
public required init(swiftValue: EncryptedMessage) {
self.swiftValue = swiftValue
}
@objc public required init(data: Data) {
self.swiftValue = EncryptedMessage(data: data)
}
@objc public required init(base64Encoded base64String: String) throws {
self.swiftValue = try EncryptedMessage(base64Encoded: base64String)
}
@objc public func decrypted(with key: _objc_PrivateKey, padding: Padding) throws -> _objc_ClearMessage {
let clearMessage = try swiftValue.decrypted(with: key.swiftValue, padding: padding)
return _objc_ClearMessage(swiftValue: clearMessage)
}
}
// MARK: - Signature
@objc(Signature)
public class _objc_Signature: NSObject, ObjcBridgeable { // swiftlint:disable:this type_name
@objc
public enum DigestType: Int {
case sha1
case sha224
case sha256
case sha384
case sha512
fileprivate var swiftValue: Signature.DigestType {
switch self {
case .sha1: return .sha1
case .sha224: return .sha224
case .sha256: return .sha256
case .sha384: return .sha384
case .sha512: return .sha512
}
}
}
fileprivate let swiftValue: Signature
@objc public var base64String: String {
return swiftValue.base64String
}
@objc public var data: Data {
return swiftValue.data
}
public required init(swiftValue: Signature) {
self.swiftValue = swiftValue
}
@objc public init(data: Data) {
self.swiftValue = Signature(data: data)
}
@objc public required init(base64Encoded base64String: String) throws {
self.swiftValue = try Signature(base64Encoded: base64String)
}
}

19
Pods/SwiftyRSA/Source/SwiftyRSA.h generated Normal file
View File

@@ -0,0 +1,19 @@
//
// SwiftyRSA.h
// SwiftyRSA
//
// Created by Loïs Di Qual on 7/2/15.
// Copyright (c) 2015 Scoop. All rights reserved.
//
@import Foundation;
//! Project version number for SwiftyRSA.
FOUNDATION_EXPORT double SwiftyRSAVersionNumber;
//! Project version string for SwiftyRSA.
FOUNDATION_EXPORT const unsigned char SwiftyRSAVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <SwiftyRSA/PublicHeader.h>
#import "NSData+SHA.h"

349
Pods/SwiftyRSA/Source/SwiftyRSA.swift generated Normal file
View File

@@ -0,0 +1,349 @@
//
// SwiftyRSA.swift
// SwiftyRSA
//
// Created by Loïs Di Qual on 7/2/15.
//
// Copyright (c) 2015 Scoop Technologies, Inc. All rights reserved.
//
import Foundation
import Security
public typealias Padding = SecPadding
public enum SwiftyRSA {
static func base64String(pemEncoded pemString: String) throws -> String {
let lines = pemString.components(separatedBy: "\n").filter { line in
return !line.hasPrefix("-----BEGIN") && !line.hasPrefix("-----END")
}
guard lines.count != 0 else {
throw SwiftyRSAError.pemDoesNotContainKey
}
return lines.joined(separator: "")
}
static func isValidKeyReference(_ reference: SecKey, forClass requiredClass: CFString) -> Bool {
guard #available(iOS 10.0, *), #available(watchOS 3.0, *), #available(tvOS 10.0, *) else {
return true
}
let attributes = SecKeyCopyAttributes(reference) as? [CFString: Any]
guard let keyType = attributes?[kSecAttrKeyType] as? String, let keyClass = attributes?[kSecAttrKeyClass] as? String else {
return false
}
let isRSA = keyType == (kSecAttrKeyTypeRSA as String)
let isValidClass = keyClass == (requiredClass as String)
return isRSA && isValidClass
}
static func format(keyData: Data, withPemType pemType: String) -> String {
func split(_ str: String, byChunksOfLength length: Int) -> [String] {
return stride(from: 0, to: str.count, by: length).map { index -> String in
let startIndex = str.index(str.startIndex, offsetBy: index)
let endIndex = str.index(startIndex, offsetBy: length, limitedBy: str.endIndex) ?? str.endIndex
return String(str[startIndex..<endIndex])
}
}
// Line length is typically 64 characters, except the last line.
// See https://tools.ietf.org/html/rfc7468#page-6 (64base64char)
// See https://tools.ietf.org/html/rfc7468#page-11 (example)
let chunks = split(keyData.base64EncodedString(), byChunksOfLength: 64)
let pem = [
"-----BEGIN \(pemType)-----",
chunks.joined(separator: "\n"),
"-----END \(pemType)-----"
]
return pem.joined(separator: "\n")
}
static func data(forKeyReference reference: SecKey) throws -> Data {
// On iOS+, we can use `SecKeyCopyExternalRepresentation` directly
if #available(iOS 10.0, *), #available(watchOS 3.0, *), #available(tvOS 10.0, *) {
var error: Unmanaged<CFError>?
let data = SecKeyCopyExternalRepresentation(reference, &error)
guard let unwrappedData = data as Data? else {
throw SwiftyRSAError.keyRepresentationFailed(error: error?.takeRetainedValue())
}
return unwrappedData
// On iOS 8/9, we need to add the key again to the keychain with a temporary tag, grab the data,
// and delete the key again.
} else {
let temporaryTag = UUID().uuidString
let addParams: [CFString: Any] = [
kSecValueRef: reference,
kSecReturnData: true,
kSecClass: kSecClassKey,
kSecAttrApplicationTag: temporaryTag
]
var data: AnyObject?
let addStatus = SecItemAdd(addParams as CFDictionary, &data)
guard let unwrappedData = data as? Data else {
throw SwiftyRSAError.keyAddFailed(status: addStatus)
}
let deleteParams: [CFString: Any] = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: temporaryTag
]
_ = SecItemDelete(deleteParams as CFDictionary)
return unwrappedData
}
}
/// Will generate a new private and public key
///
/// - Parameters:
/// - size: Indicates the total number of bits in this cryptographic key
/// - Returns: A touple of a private and public key
/// - Throws: Throws and error if the tag cant be parsed or if keygeneration fails
@available(iOS 10.0, watchOS 3.0, tvOS 10.0, *)
public static func generateRSAKeyPair(sizeInBits size: Int) throws -> (privateKey: PrivateKey, publicKey: PublicKey) {
return try generateRSAKeyPair(sizeInBits: size, applyUnitTestWorkaround: false)
}
@available(iOS 10.0, watchOS 3.0, tvOS 10.0, *)
static func generateRSAKeyPair(sizeInBits size: Int, applyUnitTestWorkaround: Bool = false) throws -> (privateKey: PrivateKey, publicKey: PublicKey) {
guard let tagData = UUID().uuidString.data(using: .utf8) else {
throw SwiftyRSAError.stringToDataConversionFailed
}
// @hack Don't store permanently when running unit tests, otherwise we'll get a key creation error (NSOSStatusErrorDomain -50)
// @see http://www.openradar.me/36809637
// @see https://stackoverflow.com/q/48414685/646960
let isPermanent = applyUnitTestWorkaround ? false : true
let attributes: [CFString: Any] = [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeySizeInBits: size,
kSecPrivateKeyAttrs: [
kSecAttrIsPermanent: isPermanent,
kSecAttrApplicationTag: tagData
]
]
var error: Unmanaged<CFError>?
guard let privKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error),
let pubKey = SecKeyCopyPublicKey(privKey) else {
throw SwiftyRSAError.keyGenerationFailed(error: error?.takeRetainedValue())
}
let privateKey = try PrivateKey(reference: privKey)
let publicKey = try PublicKey(reference: pubKey)
return (privateKey: privateKey, publicKey: publicKey)
}
static func addKey(_ keyData: Data, isPublic: Bool, tag: String) throws -> SecKey {
let keyData = keyData
guard let tagData = tag.data(using: .utf8) else {
throw SwiftyRSAError.tagEncodingFailed
}
let keyClass = isPublic ? kSecAttrKeyClassPublic : kSecAttrKeyClassPrivate
// On iOS 10+, we can use SecKeyCreateWithData without going through the keychain
if #available(iOS 10.0, *), #available(watchOS 3.0, *), #available(tvOS 10.0, *) {
let sizeInBits = keyData.count * 8
let keyDict: [CFString: Any] = [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: keyClass,
kSecAttrKeySizeInBits: NSNumber(value: sizeInBits),
kSecReturnPersistentRef: true
]
var error: Unmanaged<CFError>?
guard let key = SecKeyCreateWithData(keyData as CFData, keyDict as CFDictionary, &error) else {
throw SwiftyRSAError.keyCreateFailed(error: error?.takeRetainedValue())
}
return key
// On iOS 9 and earlier, add a persistent version of the key to the system keychain
} else {
let persistKey = UnsafeMutablePointer<AnyObject?>(mutating: nil)
let keyAddDict: [CFString: Any] = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: tagData,
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecValueData: keyData,
kSecAttrKeyClass: keyClass,
kSecReturnPersistentRef: true,
kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlock
]
let addStatus = SecItemAdd(keyAddDict as CFDictionary, persistKey)
guard addStatus == errSecSuccess || addStatus == errSecDuplicateItem else {
throw SwiftyRSAError.keyAddFailed(status: addStatus)
}
let keyCopyDict: [CFString: Any] = [
kSecClass: kSecClassKey,
kSecAttrApplicationTag: tagData,
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: keyClass,
kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlock,
kSecReturnRef: true,
]
// Now fetch the SecKeyRef version of the key
var keyRef: AnyObject?
let copyStatus = SecItemCopyMatching(keyCopyDict as CFDictionary, &keyRef)
guard let unwrappedKeyRef = keyRef else {
throw SwiftyRSAError.keyCopyFailed(status: copyStatus)
}
return unwrappedKeyRef as! SecKey // swiftlint:disable:this force_cast
}
}
/**
This method strips the x509 header from a provided ASN.1 DER key.
If the key doesn't contain a header, the DER data is returned as is.
Supported formats are:
Headerless:
SEQUENCE
INTEGER (1024 or 2048 bit) -- modulo
INTEGER -- public exponent
With x509 header:
SEQUENCE
SEQUENCE
OBJECT IDENTIFIER 1.2.840.113549.1.1.1
NULL
BIT STRING
SEQUENCE
INTEGER (1024 or 2048 bit) -- modulo
INTEGER -- public exponent
Example of headerless key:
https://lapo.it/asn1js/#3082010A0282010100C1A0DFA367FBC2A5FD6ED5A071E02A4B0617E19C6B5AD11BB61192E78D212F10A7620084A3CED660894134D4E475BAD7786FA1D40878683FD1B7A1AD9C0542B7A666457A270159DAC40CE25B2EAE7CCD807D31AE725CA394F90FBB5C5BA500545B99C545A9FE08EFF00A5F23457633E1DB84ED5E908EF748A90F8DFCCAFF319CB0334705EA012AF15AA090D17A9330159C9AFC9275C610BB9B7C61317876DC7386C723885C100F774C19830F475AD1E9A9925F9CA9A69CE0181A214DF2EB75FD13E6A546B8C8ED699E33A8521242B7E42711066AEC22D25DD45D56F94D3170D6F2C25164D2DACED31C73963BA885ADCB706F40866B8266433ED5161DC50E4B3B0203010001
Example of key with X509 header (notice the additional ASN.1 sequence):
https://lapo.it/asn1js/#30819F300D06092A864886F70D010101050003818D0030818902818100D0674615A252ED3D75D2A3073A0A8A445F3188FD3BEB8BA8584F7299E391BDEC3427F287327414174997D147DD8CA62647427D73C9DA5504E0A3EED5274A1D50A1237D688486FADB8B82061675ABFA5E55B624095DB8790C6DBCAE83D6A8588C9A6635D7CF257ED1EDE18F04217D37908FD0CBB86B2C58D5F762E6207FF7B92D0203010001
*/
static func stripKeyHeader(keyData: Data) throws -> Data {
let node: Asn1Parser.Node
do {
node = try Asn1Parser.parse(data: keyData)
} catch {
throw SwiftyRSAError.asn1ParsingFailed
}
// Ensure the raw data is an ASN1 sequence
guard case .sequence(let nodes) = node else {
throw SwiftyRSAError.invalidAsn1RootNode
}
// Detect whether the sequence only has integers, in which case it's a headerless key
let onlyHasIntegers = nodes.filter { node -> Bool in
if case .integer = node {
return false
}
return true
}.isEmpty
// Headerless key
if onlyHasIntegers {
return keyData
}
// If last element of the sequence is a bit string, return its data
if let last = nodes.last, case .bitString(let data) = last {
return data
}
// If last element of the sequence is an octet string, return its data
if let last = nodes.last, case .octetString(let data) = last {
return data
}
// Unable to extract bit/octet string or raw integer sequence
throw SwiftyRSAError.invalidAsn1Structure
}
/**
This method prepend the x509 header to the given PublicKey data.
If the key already contain a x509 header, the given data is returned as is.
It letterally does the opposite of the previous method :
From a given headerless key :
SEQUENCE
INTEGER (1024 or 2048 bit) -- modulo
INTEGER -- public exponent
the key is returned following the X509 header :
SEQUENCE
SEQUENCE
OBJECT IDENTIFIER 1.2.840.113549.1.1.1
NULL
BIT STRING
SEQUENCE
INTEGER (1024 or 2048 bit) -- modulo
INTEGER -- public exponent
*/
static func prependX509KeyHeader(keyData: Data) throws -> Data {
if try keyData.isAnHeaderlessKey() {
let x509certificate: Data = keyData.prependx509Header()
return x509certificate
} else if try keyData.hasX509Header() {
return keyData
} else { // invalideHeader
throw SwiftyRSAError.x509CertificateFailed
}
}
static func removeKey(tag: String) {
guard let tagData = tag.data(using: .utf8) else {
return
}
let keyRemoveDict: [CFString: Any] = [
kSecClass: kSecClassKey,
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrApplicationTag: tagData,
]
SecItemDelete(keyRemoveDict as CFDictionary)
}
}
#if !swift(>=4.1)
extension Array {
func compactMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult] {
return try self.flatMap(transform)
}
}
#endif
#if !swift(>=4.0)
extension NSTextCheckingResult {
func range(at idx: Int) -> NSRange {
return self.rangeAt(1)
}
}
#endif

View File

@@ -0,0 +1,88 @@
//
// SwiftyRSAError.swift
// SwiftyRSA
//
// Created by Lois Di Qual on 5/15/17.
// Contributions by Stchepinsky Nathan on 24/06/2021
// Copyright © 2017 Scoop. All rights reserved.
//
import Foundation
public enum SwiftyRSAError: Error {
case pemDoesNotContainKey
case keyRepresentationFailed(error: CFError?)
case keyGenerationFailed(error: CFError?)
case keyCreateFailed(error: CFError?)
case keyAddFailed(status: OSStatus)
case keyCopyFailed(status: OSStatus)
case tagEncodingFailed
case asn1ParsingFailed
case invalidAsn1RootNode
case invalidAsn1Structure
case invalidBase64String
case chunkDecryptFailed(index: Int)
case chunkEncryptFailed(index: Int)
case stringToDataConversionFailed
case dataToStringConversionFailed
case invalidDigestSize(digestSize: Int, maxChunkSize: Int)
case signatureCreateFailed(status: OSStatus)
case signatureVerifyFailed(status: OSStatus)
case pemFileNotFound(name: String)
case derFileNotFound(name: String)
case notAPublicKey
case notAPrivateKey
case x509CertificateFailed
var localizedDescription: String {
switch self {
case .pemDoesNotContainKey:
return "Couldn't get data from PEM key: no data available after stripping headers"
case .keyRepresentationFailed(let error):
return "Couldn't retrieve key data from the keychain: CFError \(String(describing: error))"
case .keyGenerationFailed(let error):
return "Couldn't generate key pair: CFError: \(String(describing: error))"
case .keyCreateFailed(let error):
return "Couldn't create key reference from key data: CFError \(String(describing: error))"
case .keyAddFailed(let status):
return "Couldn't retrieve key data from the keychain: OSStatus \(status)"
case .keyCopyFailed(let status):
return "Couldn't copy and retrieve key reference from the keychain: OSStatus \(status)"
case .tagEncodingFailed:
return "Couldn't create tag data for key"
case .asn1ParsingFailed:
return "Couldn't parse the ASN1 key data. Please file a bug at https://goo.gl/y67MW6"
case .invalidAsn1RootNode:
return "Couldn't parse the provided key because its root ASN1 node is not a sequence. The key is probably corrupt"
case .invalidAsn1Structure:
return "Couldn't parse the provided key because it has an unexpected ASN1 structure"
case .invalidBase64String:
return "The provided string is not a valid Base 64 string"
case .chunkDecryptFailed(let index):
return "Couldn't decrypt chunk at index \(index)"
case .chunkEncryptFailed(let index):
return "Couldn't encrypt chunk at index \(index)"
case .stringToDataConversionFailed:
return "Couldn't convert string to data using specified encoding"
case .dataToStringConversionFailed:
return "Couldn't convert data to string representation"
case .invalidDigestSize(let digestSize, let maxChunkSize):
return "Provided digest type produces a size (\(digestSize)) that is bigger than the maximum chunk size \(maxChunkSize) of the RSA key"
case .signatureCreateFailed(let status):
return "Couldn't sign provided data: OSStatus \(status)"
case .signatureVerifyFailed(let status):
return "Couldn't verify signature of the provided data: OSStatus \(status)"
case .pemFileNotFound(let name):
return "Couldn't find a PEM file named '\(name)'"
case .derFileNotFound(let name):
return "Couldn't find a DER file named '\(name)'"
case .notAPublicKey:
return "Provided key is not a valid RSA public key"
case .notAPrivateKey:
return "Provided key is not a valid RSA pivate key"
case .x509CertificateFailed :
return "Couldn't prepend the provided key because it has an unexpected structure"
}
}
}

View File

@@ -0,0 +1,163 @@
//
// X509Certificate.swift
// SwiftyRSA
//
// Created by Stchepinsky Nathan on 24/06/2021.
// Copyright © 2021 Scoop. All rights reserved.
//
import Foundation
/// Encoding/Decoding lengths as octets
private extension NSInteger {
func encodedOctets() -> [CUnsignedChar] {
// Short form
if self < 128 {
return [CUnsignedChar(self)]
}
// Long form
let long = Int(log2(Double(self)) / 8 + 1)
var len = self
var result: [CUnsignedChar] = [CUnsignedChar(long + 0x80)]
for _ in 0..<long {
result.insert(CUnsignedChar(len & 0xFF), at: 1)
len = len >> 8
}
return result
}
init?(octetBytes: [CUnsignedChar], startIdx: inout NSInteger) {
if octetBytes[startIdx] < 128 {
// Short form
self.init(octetBytes[startIdx])
startIdx += 1
} else {
// Long form
let octets = NSInteger(octetBytes[startIdx] as UInt8 - 128)
if octets > octetBytes.count - startIdx {
self.init(0)
return nil
}
var result = UInt64(0)
for octet in 1...octets {
result = (result << 8)
result = result + UInt64(octetBytes[startIdx + octet])
}
startIdx += 1 + octets
self.init(result)
}
}
}
public extension Data {
// This code source come from Heimdall project https://github.com/henrinormak/Heimdall published under MIT Licence
/// This method prepend the X509 header to a given public key
func prependx509Header() -> Data {
let result = NSMutableData()
let encodingLength: Int = (self.count + 1).encodedOctets().count
let OID: [CUnsignedChar] = [0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00]
var builder: [CUnsignedChar] = []
// ASN.1 SEQUENCE
builder.append(0x30)
// Overall size, made of OID + bitstring encoding + actual key
let size = OID.count + 2 + encodingLength + self.count
let encodedSize = size.encodedOctets()
builder.append(contentsOf: encodedSize)
result.append(builder, length: builder.count)
result.append(OID, length: OID.count)
builder.removeAll(keepingCapacity: false)
builder.append(0x03)
builder.append(contentsOf: (self.count + 1).encodedOctets())
builder.append(0x00)
result.append(builder, length: builder.count)
// Actual key bytes
result.append(self)
return result as Data
}
func hasX509Header() throws -> Bool {
let node: Asn1Parser.Node
do {
node = try Asn1Parser.parse(data: self)
} catch {
throw SwiftyRSAError.asn1ParsingFailed
}
// Ensure the raw data is an ASN1 sequence
guard case .sequence(let nodes) = node else {
return false
}
// Must contain 2 elements, a sequence and a bit string
if nodes.count != 2 {
return false
}
// Ensure the first node is an ASN1 sequence
guard case .sequence(let firstNode) = nodes[0] else {
return false
}
// Must contain 2 elements, an object id and NULL
if firstNode.count != 2 {
return false
}
guard case .objectIdentifier(_) = firstNode[0] else {
return false
}
guard case .null = firstNode[1] else {
return false
}
// The 2sd child has to be a bit string containing a sequence of 2 int
let last = nodes[1]
if case .bitString(let secondChildSequence) = last {
return try secondChildSequence.isAnHeaderlessKey()
} else {
return false
}
}
func isAnHeaderlessKey() throws -> Bool {
let node: Asn1Parser.Node
do {
node = try Asn1Parser.parse(data: self)
} catch {
throw SwiftyRSAError.asn1ParsingFailed
}
// Ensure the raw data is an ASN1 sequence
guard case .sequence(let nodes) = node else {
return false
}
// Detect whether the sequence only has integers, in which case it's a headerless key
let onlyHasIntegers = nodes.filter { node -> Bool in
if case .integer = node {
return false
}
return true
}.isEmpty
// Headerless key
return onlyHasIntegers
}
}