123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- //
- // CryptoSwift
- //
- // Copyright (C) 2014-2021 Marcin Krzyżanowski <marcin@krzyzanowskim.com>
- // This software is provided 'as-is', without any express or implied warranty.
- //
- // In no event will the authors be held liable for any damages arising from the use of this software.
- //
- // Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
- //
- // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
- // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
- // - This notice may not be removed or altered from any source or binary distribution.
- //
- // Foundation is required for `Data` to be found
- import Foundation
- // Note: The `BigUInt` struct was copied from:
- // https://github.com/attaswift/BigInt
- // It allows fast calculation for RSA big numbers
- public final class RSA: DERCodable {
- /// RSA Key Errors
- public enum Error: Swift.Error {
- /// No private key specified
- case noPrivateKey
- /// Failed to calculate the inverse e and phi
- case invalidInverseNotCoprimes
- /// We only support Version 0 RSA keys (we don't support Version 1 introduced in RFC 3447)
- case unsupportedRSAVersion
- /// Failed to verify primes during initialiization (the provided primes don't reproduce the provided private exponent)
- case invalidPrimes
- /// We attempted to export a private key without our underlying primes
- case noPrimes
- /// Unable to calculate the coefficient during a private key import / export
- case unableToCalculateCoefficient
- /// The signature to verify is of an invalid length
- case invalidSignatureLength
- /// The message to be signed is of an invalid length
- case invalidMessageLengthForSigning
- /// The message to be encrypted is of an invalid length
- case invalidMessageLengthForEncryption
- /// The error thrown when Decryption fails
- case invalidDecryption
- }
- /// RSA Modulus
- public let n: BigUInteger
- /// RSA Public Exponent
- public let e: BigUInteger
- /// RSA Private Exponent
- public let d: BigUInteger?
- /// The size of the modulus, in bits
- public let keySize: Int
- /// The size of the modulus, in bytes (rounded up to the nearest full byte)
- public let keySizeBytes: Int
- /// The underlying primes used to generate the Private Exponent
- private let primes: (p: BigUInteger, q: BigUInteger)?
- /// Initialize with RSA parameters
- /// - Parameters:
- /// - n: The RSA Modulus
- /// - e: The RSA Public Exponent
- /// - d: The RSA Private Exponent (or nil if unknown, e.g. if only public key is known)
- public init(n: BigUInteger, e: BigUInteger, d: BigUInteger? = nil) {
- self.n = n
- self.e = e
- self.d = d
- self.primes = nil
- self.keySize = n.bitWidth
- self.keySizeBytes = n.byteWidth
- }
- /// Initialize with RSA parameters
- /// - Parameters:
- /// - n: The RSA Modulus
- /// - e: The RSA Public Exponent
- /// - d: The RSA Private Exponent (or nil if unknown, e.g. if only public key is known)
- public convenience init(n: Array<UInt8>, e: Array<UInt8>, d: Array<UInt8>? = nil) {
- if let d = d {
- self.init(n: BigUInteger(Data(n)), e: BigUInteger(Data(e)), d: BigUInteger(Data(d)))
- } else {
- self.init(n: BigUInteger(Data(n)), e: BigUInteger(Data(e)))
- }
- }
- /// Initialize with a generated key pair
- /// - Parameter keySize: The size of the modulus
- public convenience init(keySize: Int) throws {
- // Generate prime numbers
- let p = BigUInteger.generatePrime(keySize / 2)
- let q = BigUInteger.generatePrime(keySize / 2)
- // Calculate modulus
- let n = p * q
- // Calculate public and private exponent
- let e: BigUInteger = 65537
- let phi = (p - 1) * (q - 1)
- guard let d = e.inverse(phi) else {
- throw RSA.Error.invalidInverseNotCoprimes
- }
- // Initialize
- self.init(n: n, e: e, d: d, p: p, q: q)
- }
- /// Initialize with RSA parameters
- /// - Parameters:
- /// - n: The RSA Modulus
- /// - e: The RSA Public Exponent
- /// - d: The RSA Private Exponent
- /// - p: The 1st Prime used to generate the Private Exponent
- /// - q: The 2nd Prime used to generate the Private Exponent
- private init(n: BigUInteger, e: BigUInteger, d: BigUInteger, p: BigUInteger, q: BigUInteger) {
- self.n = n
- self.e = e
- self.d = d
- self.primes = (p, q)
- self.keySize = n.bitWidth
- self.keySizeBytes = n.byteWidth
- }
- }
- // MARK: BigUInt Extension
- internal extension CS.BigUInt {
- /// The minimum number of bytes required to represent this integer in binary.
- var byteWidth: Int {
- let bytes = self.bitWidth / 8
- return self.bitWidth % 8 == 0 ? bytes : bytes + 1
- }
- }
- // MARK: DER Initializers (See #892)
- extension RSA {
- /// Decodes the provided data into a Public RSA Key
- ///
- /// [IETF Spec RFC2313](https://datatracker.ietf.org/doc/html/rfc2313#section-7.1)
- /// ```
- /// =========================
- /// RSA PublicKey Structure
- /// =========================
- ///
- /// RSAPublicKey ::= SEQUENCE {
- /// modulus INTEGER, -- n
- /// publicExponent INTEGER, -- e
- /// }
- /// ```
- internal convenience init(publicDER der: Array<UInt8>) throws {
- let asn = try ASN1.Decoder.decode(data: Data(der))
- // Enforce the above ASN Structure
- guard case .sequence(let params) = asn else { throw DER.Error.invalidDERFormat }
- guard params.count == 2 else { throw DER.Error.invalidDERFormat }
- guard case .integer(let modulus) = params[0] else { throw DER.Error.invalidDERFormat }
- guard case .integer(let publicExponent) = params[1] else { throw DER.Error.invalidDERFormat }
- self.init(n: BigUInteger(modulus), e: BigUInteger(publicExponent))
- }
- /// Decodes the provided data into a Private RSA Key
- ///
- /// [IETF Spec RFC2313](https://datatracker.ietf.org/doc/html/rfc2313#section-7.2)
- /// ```
- /// ==========================
- /// RSA PrivateKey Structure
- /// ==========================
- ///
- /// RSAPrivateKey ::= SEQUENCE {
- /// version Version,
- /// modulus INTEGER, -- n
- /// publicExponent INTEGER, -- e
- /// privateExponent INTEGER, -- d
- /// prime1 INTEGER, -- p
- /// prime2 INTEGER, -- q
- /// exponent1 INTEGER, -- d mod (p-1)
- /// exponent2 INTEGER, -- d mod (q-1)
- /// coefficient INTEGER, -- (inverse of q) mod p
- /// }
- /// ```
- internal convenience init(privateDER der: Array<UInt8>) throws {
- let asn = try ASN1.Decoder.decode(data: Data(der))
- // Enforce the above ASN Structure (do we need to extract and verify the eponents and coefficients?)
- guard case .sequence(let params) = asn else { throw DER.Error.invalidDERFormat }
- guard params.count == 9 else { throw DER.Error.invalidDERFormat }
- guard case .integer(let version) = params[0] else { throw DER.Error.invalidDERFormat }
- guard case .integer(let modulus) = params[1] else { throw DER.Error.invalidDERFormat }
- guard case .integer(let publicExponent) = params[2] else { throw DER.Error.invalidDERFormat }
- guard case .integer(let privateExponent) = params[3] else { throw DER.Error.invalidDERFormat }
- guard case .integer(let prime1) = params[4] else { throw DER.Error.invalidDERFormat }
- guard case .integer(let prime2) = params[5] else { throw DER.Error.invalidDERFormat }
- guard case .integer(let exponent1) = params[6] else { throw DER.Error.invalidDERFormat }
- guard case .integer(let exponent2) = params[7] else { throw DER.Error.invalidDERFormat }
- guard case .integer(let coefficient) = params[8] else { throw DER.Error.invalidDERFormat }
- // We only support version 0x00 == RFC2313 at the moment
- // - TODO: Support multiple primes 0x01 version defined in [RFC3447](https://www.rfc-editor.org/rfc/rfc3447#appendix-A.1.2)
- guard version == Data(hex: "0x00") else { throw Error.unsupportedRSAVersion }
- // Ensure the supplied parameters are correct...
- // Calculate modulus
- guard BigUInteger(modulus) == BigUInteger(prime1) * BigUInteger(prime2) else { throw Error.invalidPrimes }
- // Calculate public and private exponent
- let phi = (BigUInteger(prime1) - 1) * (BigUInteger(prime2) - 1)
- guard let d = BigUInteger(publicExponent).inverse(phi) else { throw Error.invalidPrimes }
- guard BigUInteger(privateExponent) == d else { throw Error.invalidPrimes }
- // Ensure the provided coefficient is correct (derived from the primes)
- guard let calculatedCoefficient = BigUInteger(prime2).inverse(BigUInteger(prime1)) else { throw RSA.Error.unableToCalculateCoefficient }
- guard calculatedCoefficient == BigUInteger(coefficient) else { throw RSA.Error.invalidPrimes }
- // Ensure the provided exponents are correct as well
- guard (d % (BigUInteger(prime1) - 1)) == BigUInteger(exponent1) else { throw RSA.Error.invalidPrimes }
- guard (d % (BigUInteger(prime2) - 1)) == BigUInteger(exponent2) else { throw RSA.Error.invalidPrimes }
- // Proceed with regular initialization
- self.init(n: BigUInteger(modulus), e: BigUInteger(publicExponent), d: BigUInteger(privateExponent), p: BigUInteger(prime1), q: BigUInteger(prime2))
- }
- /// Attempts to instantiate an RSA Key when given the ASN1 DER encoded external representation of the Key
- ///
- /// An example of importing a SecKey RSA key (from Apple's `Security` framework) for use within CryptoSwift
- /// ```
- /// /// Starting with a SecKey RSA Key
- /// let rsaSecKey:SecKey
- ///
- /// /// Copy the External Representation
- /// var externalRepError:Unmanaged<CFError>?
- /// guard let externalRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else {
- /// /// Failed to copy external representation for RSA SecKey
- /// return
- /// }
- ///
- /// /// Instantiate the RSA Key from the raw external representation
- /// let rsaKey = try RSA(rawRepresentation: externalRep)
- ///
- /// /// You now have a CryptoSwift RSA Key
- /// // rsaKey.encrypt(...)
- /// // rsaKey.decrypt(...)
- /// // rsaKey.sign(...)
- /// // rsaKey.verify(...)
- /// ```
- public convenience init(rawRepresentation raw: Data) throws {
- do { try self.init(privateDER: raw.bytes) } catch {
- try self.init(publicDER: raw.bytes)
- }
- }
- }
- // MARK: DER Exports (See #892)
- extension RSA {
- /// The DER representation of this public key
- ///
- /// [IETF Spec RFC2313](https://datatracker.ietf.org/doc/html/rfc2313#section-7.1)
- /// ```
- /// =========================
- /// RSA PublicKey Structure
- /// =========================
- ///
- /// RSAPublicKey ::= SEQUENCE {
- /// modulus INTEGER, -- n
- /// publicExponent INTEGER -- e
- /// }
- /// ```
- func publicKeyDER() throws -> Array<UInt8> {
- let mod = self.n.serialize()
- let pubKeyAsnNode: ASN1.Node =
- .sequence(nodes: [
- .integer(data: DER.i2ospData(x: mod.bytes, size: self.keySizeBytes)),
- .integer(data: DER.i2ospData(x: self.e.serialize().bytes, size: 3))
- ])
- return ASN1.Encoder.encode(pubKeyAsnNode)
- }
- /// The DER representation of this private key
- ///
- /// [IETF Spec RFC2313](https://datatracker.ietf.org/doc/html/rfc2313#section-7.2)
- /// ```
- /// ==========================
- /// RSA PrivateKey Structure
- /// ==========================
- ///
- /// RSAPrivateKey ::= SEQUENCE {
- /// version Version,
- /// modulus INTEGER, -- n
- /// publicExponent INTEGER, -- e
- /// privateExponent INTEGER, -- d
- /// prime1 INTEGER, -- p
- /// prime2 INTEGER, -- q
- /// exponent1 INTEGER, -- d mod (p-1)
- /// exponent2 INTEGER, -- d mod (q-1)
- /// coefficient INTEGER, -- (inverse of q) mod p
- /// }
- /// ```
- func privateKeyDER() throws -> Array<UInt8> {
- // Make sure we have a private key
- guard let d = d else { throw RSA.Error.noPrivateKey }
- // Make sure we have access to our primes
- guard let primes = primes else { throw RSA.Error.noPrimes }
- // Make sure we can calculate our coefficient (inverse of q mod p)
- guard let coefficient = primes.q.inverse(primes.p) else { throw RSA.Error.unableToCalculateCoefficient }
- let paramWidth = self.keySizeBytes / 2
- // Structure the data (according to RFC2313, version 0x00 RSA Private Key Syntax)
- let mod = self.n.serialize()
- let privateKeyAsnNode: ASN1.Node =
- .sequence(nodes: [
- .integer(data: Data(hex: "0x00")),
- .integer(data: DER.i2ospData(x: mod.bytes, size: self.keySizeBytes)),
- .integer(data: DER.i2ospData(x: self.e.serialize().bytes, size: 3)),
- .integer(data: DER.i2ospData(x: d.serialize().bytes, size: self.keySizeBytes)),
- .integer(data: DER.i2ospData(x: primes.p.serialize().bytes, size: paramWidth)),
- .integer(data: DER.i2ospData(x: primes.q.serialize().bytes, size: paramWidth)),
- .integer(data: DER.i2ospData(x: (d % (primes.p - 1)).serialize().bytes, size: paramWidth)),
- .integer(data: DER.i2ospData(x: (d % (primes.q - 1)).serialize().bytes, size: paramWidth)),
- .integer(data: DER.i2ospData(x: coefficient.serialize().bytes, size: paramWidth))
- ])
- // Encode and return the data
- return ASN1.Encoder.encode(privateKeyAsnNode)
- }
- /// This method returns the DER encoding of the RSA Key.
- ///
- /// - Returns: The ASN1 DER Encoding of the Public or Private RSA Key
- /// - Note: If the RSA Key is a private key, the private key representation is returned
- /// - Note: If the RSA Key is a public key, the public key representation is returned
- /// - Note: If you'd like to only export the public DER of an RSA Key call the `publicKeyExternalRepresentation()` method
- /// - Note: This method returns the same data as Apple's `SecKeyCopyExternalRepresentation` method.
- ///
- /// An example of converting a CryptoSwift RSA key to a SecKey RSA key
- /// ```
- /// /// Starting with a CryptoSwift RSA Key
- /// let rsaKey = try RSA(keySize: 1024)
- ///
- /// /// Define your Keys attributes
- /// let attributes: [String:Any] = [
- /// kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
- /// kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, // or kSecAttrKeyClassPublic
- /// kSecAttrKeySizeInBits as String: 1024, // The appropriate bits
- /// kSecAttrIsPermanent as String: false
- /// ]
- /// var error:Unmanaged<CFError>? = nil
- /// guard let rsaSecKey = try SecKeyCreateWithData(rsaKey.externalRepresentation() as CFData, attributes as CFDictionary, &error) else {
- /// /// Error constructing SecKey from raw key data
- /// return
- /// }
- ///
- /// /// You now have an RSA SecKey for use with Apple's Security framework
- /// ```
- ///
- /// An example of converting a SecKey RSA key to a CryptoSwift RSA key
- /// ```
- /// /// Starting with a SecKey RSA Key
- /// let rsaSecKey:SecKey
- ///
- /// /// Copy External Representation
- /// var externalRepError:Unmanaged<CFError>?
- /// guard let cfdata = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) else {
- /// /// Failed to copy external representation for RSA SecKey
- /// return
- /// }
- ///
- /// /// Instantiate the RSA Key from the raw external representation
- /// let rsaKey = try RSA(rawRepresentation: cfdata as Data)
- ///
- /// /// You now have a CryptoSwift RSA Key
- /// ```
- ///
- func externalRepresentation() throws -> Data {
- if self.primes != nil {
- return try Data(self.privateKeyDER())
- } else {
- return try Data(self.publicKeyDER())
- }
- }
- }
- // MARK: CS.BigUInt extension
- extension BigUInteger {
- public static func generatePrime(_ width: Int) -> BigUInteger {
- // Note: Need to find a better way to generate prime numbers
- while true {
- var random = BigUInteger.randomInteger(withExactWidth: width)
- random |= BigUInteger(1)
- if random.isPrime() {
- return random
- }
- }
- }
- }
- // MARK: CustomStringConvertible Conformance
- extension RSA: CustomStringConvertible {
- public var description: String {
- if self.d != nil {
- return "CryptoSwift.RSA.PrivateKey<\(self.keySize)>"
- } else {
- return "CryptoSwift.RSA.PublicKey<\(self.keySize)>"
- }
- }
- }
|