|
|
@@ -0,0 +1,94 @@
|
|
|
+//
|
|
|
+// CryptoSwift
|
|
|
+//
|
|
|
+// Copyright (C) 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.
|
|
|
+//
|
|
|
+
|
|
|
+import Foundation
|
|
|
+
|
|
|
+/// Conform to this protocol if your type can both be instantiated and expressed as an ASN1 DER representation.
|
|
|
+public protocol DERCodable: DERDecodable, DEREncodable { }
|
|
|
+
|
|
|
+/// Conform to this protocol if your type can be instantiated from a ASN1 DER representation
|
|
|
+public protocol DERDecodable {
|
|
|
+ /// The keys primary ASN1 object identifier (ex: for RSA Keys --> 'rsaEncryption' --> [0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01])
|
|
|
+ static var primaryObjectIdentifier: Array<UInt8> { get }
|
|
|
+ /// The keys secondary ASN1 object identifier (ex: for RSA Keys --> 'null' --> nil)
|
|
|
+ static var secondaryObjectIdentifier: Array<UInt8>? { get }
|
|
|
+
|
|
|
+ /// Instantiates an instance of your Public Key when given a DER representation of your Public Key
|
|
|
+ init(publicDER: Array<UInt8>) throws
|
|
|
+ /// Instantiates an instance of your Private Key when given a DER representation of your Private Key
|
|
|
+ init(privateDER: Array<UInt8>) throws
|
|
|
+}
|
|
|
+
|
|
|
+/// Conform to this protocol if your type can be described in an ASN1 DER representation
|
|
|
+public protocol DEREncodable {
|
|
|
+ /// The keys primary ASN1 object identifier (ex: for RSA Keys --> 'rsaEncryption' --> [0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01])
|
|
|
+ static var primaryObjectIdentifier: Array<UInt8> { get }
|
|
|
+ /// The keys secondary ASN1 object identifier (ex: for RSA Keys --> 'null' --> nil)
|
|
|
+ static var secondaryObjectIdentifier: Array<UInt8>? { get }
|
|
|
+
|
|
|
+ /// Returns the DER encoded representation of the Public Key
|
|
|
+ func publicKeyDER() throws -> Array<UInt8>
|
|
|
+ /// Returns the DER encoded representation of the Private Key
|
|
|
+ func privateKeyDER() throws -> Array<UInt8>
|
|
|
+
|
|
|
+ /// A semantically similar function that mimics the functionality of Apple's `Security` framework's `SecKeyCopyExternalRepresentation` function
|
|
|
+ /// - Note: If called on a Private Key, this method will return the Private Keys DER Representation. Likewise, if called on a Public Key, this method will return the Public Keys DER Representation
|
|
|
+ /// - Note: If you'd like to export the Public Keys DER from a Private Key, use the `publicKeyExternalRepresentation()` function
|
|
|
+ func externalRepresentation() throws -> Data
|
|
|
+ /// A semantically similar function that mimics the functionality of Apple's `Security` framework's `SecKeyCopyExternalRepresentation` function
|
|
|
+ /// - Note: This function only ever exports the Public Key's DER representation. If called on a Private Key, the corresponding Public Key will be extracted and exported.
|
|
|
+ func publicKeyExternalRepresentation() throws -> Data
|
|
|
+}
|
|
|
+
|
|
|
+extension DEREncodable {
|
|
|
+ func externalRepresentation() throws -> Data {
|
|
|
+ do { return try Data(self.privateKeyDER()) } catch {
|
|
|
+ return try Data(self.publicKeyDER())
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ func publicKeyExternalRepresentation() throws -> Data {
|
|
|
+ try Data(self.publicKeyDER())
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+struct DER {
|
|
|
+ /// Integer to Octet String Primitive
|
|
|
+ /// - Parameters:
|
|
|
+ /// - x: nonnegative integer to be converted
|
|
|
+ /// - size: intended length of the resulting octet string
|
|
|
+ /// - Returns: corresponding octet string of length xLen
|
|
|
+ /// - Note: https://datatracker.ietf.org/doc/html/rfc3447#section-4.1
|
|
|
+ internal static func i2osp(x: [UInt8], size: Int) -> [UInt8] {
|
|
|
+ var modulus = x
|
|
|
+ while modulus.count < size {
|
|
|
+ modulus.insert(0x00, at: 0)
|
|
|
+ }
|
|
|
+ if modulus[0] >= 0x80 {
|
|
|
+ modulus.insert(0x00, at: 0)
|
|
|
+ }
|
|
|
+ return modulus
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Integer to Octet String Primitive
|
|
|
+ /// - Parameters:
|
|
|
+ /// - x: nonnegative integer to be converted
|
|
|
+ /// - size: intended length of the resulting octet string
|
|
|
+ /// - Returns: corresponding octet string of length xLen
|
|
|
+ /// - Note: https://datatracker.ietf.org/doc/html/rfc3447#section-4.1
|
|
|
+ internal static func i2ospData(x: [UInt8], size: Int) -> Data {
|
|
|
+ return Data(DER.i2osp(x: x, size: size))
|
|
|
+ }
|
|
|
+}
|