From fee810b03533d0db68b4f9e2f2c8fc340b3cdc92 Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 5 Jun 2022 22:58:35 -0700 Subject: [PATCH 01/52] DERCodable conformance --- .../Keys/Types/Ed25519/Ed25519.swift | 47 +++++++++++++++++++ .../Keys/Types/Secp256k1/Secp256k1.swift | 46 ++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/Sources/LibP2PCrypto/Keys/Types/Ed25519/Ed25519.swift b/Sources/LibP2PCrypto/Keys/Types/Ed25519/Ed25519.swift index f9dfab3..ecc149d 100644 --- a/Sources/LibP2PCrypto/Keys/Types/Ed25519/Ed25519.swift +++ b/Sources/LibP2PCrypto/Keys/Types/Ed25519/Ed25519.swift @@ -7,6 +7,7 @@ import Foundation import Crypto +//import PEM extension Curve25519.Signing.PublicKey:CommonPublicKey { public static var keyType: LibP2PCrypto.Keys.GenericKeyType { .ed25519 } @@ -128,3 +129,49 @@ extension Curve25519.Signing.PrivateKey:Equatable { lhs.rawRepresentation == rhs.rawRepresentation } } + +extension Curve25519.Signing.PublicKey:DERCodable { + public static var primaryObjectIdentifier: Array { [0x2B, 0x65, 0x70] } + public static var secondaryObjectIdentifier: Array? { nil } + + public init(publicDER: Array) throws { + try self.init(rawRepresentation: publicDER) + } + + public init(privateDER: Array) throws { + throw NSError(domain: "Can't instantiate private key from public DER representation", code: 0) + } + + public func publicKeyDER() throws -> Array { + self.rawRepresentation.bytes + } + + public func privateKeyDER() throws -> Array { + throw NSError(domain: "Public Key doesn't have private DER representation", code: 0) + } +} + +extension Curve25519.Signing.PrivateKey:DERCodable { + public static var primaryObjectIdentifier: Array { [0x2B, 0x65, 0x70] } + public static var secondaryObjectIdentifier: Array? { nil } + + public init(publicDER: Array) throws { + throw NSError(domain: "Can't instantiate private key from public DER representation", code: 0) + } + + public init(privateDER: Array) throws { + guard case .octetString(let rawData) = try ASN1.Decoder.decode(data: Data(privateDER)) else { + throw PEM.Error.invalidParameters + } + try self.init(rawRepresentation: rawData) + } + + public func publicKeyDER() throws -> Array { + try self.publicKey.publicKeyDER() + } + + public func privateKeyDER() throws -> Array { + self.rawRepresentation.bytes + } +} + diff --git a/Sources/LibP2PCrypto/Keys/Types/Secp256k1/Secp256k1.swift b/Sources/LibP2PCrypto/Keys/Types/Secp256k1/Secp256k1.swift index d50aaaa..e04d76b 100644 --- a/Sources/LibP2PCrypto/Keys/Types/Secp256k1/Secp256k1.swift +++ b/Sources/LibP2PCrypto/Keys/Types/Secp256k1/Secp256k1.swift @@ -110,3 +110,49 @@ extension Secp256k1PrivateKey:CommonPrivateKey { } } + + +extension Secp256k1PublicKey:DERCodable { + public static var primaryObjectIdentifier: Array { [0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01] } + public static var secondaryObjectIdentifier: Array? { [0x2B, 0x81, 0x04, 0x00, 0x0A] } + + public convenience init(publicDER: Array) throws { + /// Expects a 0x0422 32byte long octetString as the rawRepresentation + try self.init(rawRepresentation: Data(publicDER)) + } + + public convenience init(privateDER: Array) throws { + throw NSError(domain: "Can't instantiate private key from public DER representation", code: 0) + } + + public func publicKeyDER() throws -> Array { + self.rawRepresentation.bytes + } + + public func privateKeyDER() throws -> Array { + throw NSError(domain: "Public Key doesn't have private DER representation", code: 0) + } +} + +extension Secp256k1PrivateKey:DERCodable { + public static var primaryObjectIdentifier: Array { [0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x0A] } + public static var secondaryObjectIdentifier: Array? { nil } + + public convenience init(publicDER: Array) throws { + throw NSError(domain: "Can't instantiate private key from public DER representation", code: 0) + } + + public convenience init(privateDER: Array) throws { + try self.init(rawRepresentation: Data(privateDER)) + } + + public func publicKeyDER() throws -> Array { + try self.publicKey.publicKeyDER() + } + + public func privateKeyDER() throws -> Array { + self.rawRepresentation.bytes + } + + +} From 6df92531eda25d295f9e6bba47bd02e06ad16cc1 Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 5 Jun 2022 22:58:57 -0700 Subject: [PATCH 02/52] DERCodable conformance --- .../LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift diff --git a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift new file mode 100644 index 0000000..ff9f1a6 --- /dev/null +++ b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift @@ -0,0 +1,54 @@ +// +// RSA+DER.swift +// +// +// Created by Brandon Toms on 6/5/22. +// + +import Foundation + +extension RSAPublicKey:DERCodable { + /// RSA Object Identifier Bytes + public static var primaryObjectIdentifier: Array { [42, 134, 72, 134, 247, 13, 1, 1, 1] } + + public static var secondaryObjectIdentifier: Array? { nil } + + public func publicKeyDER() throws -> Array { + return self.rawRepresentation.bytes + } + + public func privateKeyDER() throws -> Array { + throw NSError(domain: "Public Key doesn't have private DER representation", code: 0) + } + + init(publicDER: Array) throws { + try self.init(rawRepresentation: Data(publicDER)) + } + + init(privateDER: Array) throws { + throw NSError(domain: "Can't instantiate private key from public DER representation", code: 0) + } +} + +extension RSAPrivateKey: DERCodable { + /// RSA Object Identifier Bytes + public static var primaryObjectIdentifier: Array { [42, 134, 72, 134, 247, 13, 1, 1, 1] } + + static var secondaryObjectIdentifier: Array? { nil } + + func publicKeyDER() throws -> Array { + try self.derivePublicKey().rawRepresentation.bytes + } + + func privateKeyDER() throws -> Array { + self.rawRepresentation.bytes + } + + init(publicDER: Array) throws { + throw NSError(domain: "Can't instantiate private key from public DER representation", code: 0) + } + + init(privateDER: Array) throws { + try self.init(rawRepresentation: Data(privateDER)) + } +} From 12ce9f26059a4d0527e45d6fba4ebc6fcde2f9af Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 5 Jun 2022 22:59:50 -0700 Subject: [PATCH 03/52] New ASN1 Encoder / Decoder implementation --- Sources/LibP2PCrypto/PEM/ASN1/ASN1.swift | 81 +++++++++++ .../LibP2PCrypto/PEM/ASN1/ASN1Decoder.swift | 128 ++++++++++++++++++ .../LibP2PCrypto/PEM/ASN1/ASN1Encoder.swift | 55 ++++++++ .../LibP2PCrypto/PEM/ASN1/ASN1Scanner.swift | 113 ++++++++++++++++ 4 files changed, 377 insertions(+) create mode 100644 Sources/LibP2PCrypto/PEM/ASN1/ASN1.swift create mode 100644 Sources/LibP2PCrypto/PEM/ASN1/ASN1Decoder.swift create mode 100644 Sources/LibP2PCrypto/PEM/ASN1/ASN1Encoder.swift create mode 100644 Sources/LibP2PCrypto/PEM/ASN1/ASN1Scanner.swift diff --git a/Sources/LibP2PCrypto/PEM/ASN1/ASN1.swift b/Sources/LibP2PCrypto/PEM/ASN1/ASN1.swift new file mode 100644 index 0000000..388a898 --- /dev/null +++ b/Sources/LibP2PCrypto/PEM/ASN1/ASN1.swift @@ -0,0 +1,81 @@ +// +// Original Asn1Parser.swift from SwiftyRSA +// +// Created by Lois Di Qual on 5/9/17. +// Copyright © 2017 Scoop. All rights reserved. +// +// Modified by Brandon Toms on 5/1/22 +// + +import Foundation + +enum ASN1 { + internal enum IDENTIFIERS:UInt8, Equatable { + case SEQUENCE = 0x30 + case INTERGER = 0x02 + case OBJECTID = 0x06 + case NULL = 0x05 + case BITSTRING = 0x03 + case OCTETSTRING = 0x04 + case EC_OBJECT = 0xA0 + case EC_BITS = 0xA1 + + static func == (lhs:UInt8, rhs:IDENTIFIERS) -> Bool { + lhs == rhs.rawValue + } + + var bytes:[UInt8] { + switch self { + case .NULL: + return [self.rawValue, 0x00] + default: + return [self.rawValue] + } + } + } + + /// An ASN1 node + enum Node:CustomStringConvertible { + case sequence(nodes: [Node]) + case integer(data: Data) + case objectIdentifier(data: Data) + case null + case bitString(data: Data) + case octetString(data: Data) + case ecObject(data: Data) + case ecBits(data: Data) + + var description: String { + ASN1.printNode(self, level: 0) + } + + } + + internal static func printNode(_ node:ASN1.Node, level:Int) -> String { + var str:[String] = [] + let prefix = String(repeating: "\t", count: level) + switch node { + case .integer(let int): + str.append("\(prefix)Integer: \(int.toHexString())") + case .bitString(let bs): + str.append("\(prefix)BitString: \(bs.toHexString())") + case .null: + str.append("\(prefix)NULL") + case .objectIdentifier(let oid): + str.append("\(prefix)ObjectID: \(oid.toHexString())") + case .octetString(let os): + str.append("\(prefix)OctetString: \(os.toHexString())") + case .ecObject(let ecObj): + str.append("\(prefix)EC Object: \(ecObj.toHexString())") + case .ecBits(let ecBits): + str.append("\(prefix)EC Bits: \(ecBits.toHexString())") + case .sequence(let nodes): + str.append("\(prefix)Sequence:") + nodes.forEach { str.append(printNode($0, level: level + 1)) } + } + return str.joined(separator: "\n") + } +} + + + diff --git a/Sources/LibP2PCrypto/PEM/ASN1/ASN1Decoder.swift b/Sources/LibP2PCrypto/PEM/ASN1/ASN1Decoder.swift new file mode 100644 index 0000000..890b469 --- /dev/null +++ b/Sources/LibP2PCrypto/PEM/ASN1/ASN1Decoder.swift @@ -0,0 +1,128 @@ +// +// File.swift +// +// +// Created by Brandon Toms on 5/28/22. +// + +import Foundation + +extension ASN1 { + /// 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 Decoder { + + enum DecodingError: 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 DecodingError if anything goes wrong, or if an unknown node was encountered + static func decode(data: Data) throws -> Node { + let scanner = Scanner(data: data) + let node = try decodeNode(scanner: scanner) + return node + } + + /// Parses an ASN1 given an existing scanner. + /// @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 DecodingError if anything goes wrong, or if an unknown node was encountered + private static func decodeNode(scanner: Scanner) throws -> Node { + + let firstByte = try scanner.consume(length: 1).firstByte + + // Sequence + if firstByte == IDENTIFIERS.SEQUENCE { + let length = try scanner.consumeLength() + let data = try scanner.consume(length: length) + let nodes = try decodeSequence(data: data) + return .sequence(nodes: nodes) + } + + // Integer + if firstByte == IDENTIFIERS.INTERGER { + let length = try scanner.consumeLength() + let data = try scanner.consume(length: length) + return .integer(data: data) + } + + // Object identifier + if firstByte == IDENTIFIERS.OBJECTID { + let length = try scanner.consumeLength() + let data = try scanner.consume(length: length) + return .objectIdentifier(data: data) + } + + // Null + if firstByte == IDENTIFIERS.NULL { + _ = try scanner.consume(length: 1) + return .null + } + + // Bit String + if firstByte == IDENTIFIERS.BITSTRING { + 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 == IDENTIFIERS.OCTETSTRING { + let length = try scanner.consumeLength() + let data = try scanner.consume(length: length) + return .octetString(data: data) + } + + // EC Curves Cont 0 identifier (obj id) + if firstByte == IDENTIFIERS.EC_OBJECT { + let length = try scanner.consumeLength() + let data = try scanner.consume(length: length) + //print("Found an EC Curve Obj ID: [\(data.map { "\($0)" }.joined(separator: ","))]") + return .objectIdentifier(data: data) + } + + // EC Curves Cont 1 identifier (bit string) + if firstByte == IDENTIFIERS.EC_BITS { + 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) + //print("Found an EC Curve Bit String: [\(data.map { "\($0)" }.joined(separator: ","))]") + return .bitString(data: data) + } + + throw DecodingError.invalidType(value: firstByte) + } + + /// Parses an ASN1 sequence and returns its child nodes + /// + /// - Parameter data: ASN1 data + /// - Returns: A list of ASN1 nodes + /// - Throws: A DecodingError if anything goes wrong, or if an unknown node was encountered + private static func decodeSequence(data: Data) throws -> [Node] { + let scanner = Scanner(data: data) + var nodes: [Node] = [] + while !scanner.isComplete { + let node = try decodeNode(scanner: scanner) + nodes.append(node) + } + return nodes + } + } +} diff --git a/Sources/LibP2PCrypto/PEM/ASN1/ASN1Encoder.swift b/Sources/LibP2PCrypto/PEM/ASN1/ASN1Encoder.swift new file mode 100644 index 0000000..2e14fd7 --- /dev/null +++ b/Sources/LibP2PCrypto/PEM/ASN1/ASN1Encoder.swift @@ -0,0 +1,55 @@ +// +// File.swift +// +// +// Created by Brandon Toms on 5/28/22. +// + +import Foundation + +extension ASN1 { + enum Encoder { + /// Encodes an ASN1Node into it's byte representation + /// + /// - Parameter node: The Node to encode + /// - Returns: The encoded bytes as a UInt8 array + public static func encode(_ node:ASN1.Node) -> [UInt8] { + switch node { + case .integer(let integer): + return IDENTIFIERS.INTERGER.bytes + asn1LengthPrefixed(integer.bytes) + case .bitString(let bits): + return IDENTIFIERS.BITSTRING.bytes + asn1LengthPrefixed([0x00] + bits.bytes) + case .octetString(let octet): + return IDENTIFIERS.OCTETSTRING.bytes + asn1LengthPrefixed(octet.bytes) + case .null: + return IDENTIFIERS.NULL.bytes + case .objectIdentifier(let oid): + return IDENTIFIERS.OBJECTID.bytes + asn1LengthPrefixed(oid.bytes) + case .ecObject(let ecObj): + return IDENTIFIERS.EC_OBJECT.bytes + asn1LengthPrefixed(ecObj.bytes) + case .ecBits(let ecBits): + return IDENTIFIERS.EC_BITS.bytes + asn1LengthPrefixed(ecBits.bytes) + case .sequence(let nodes): + return IDENTIFIERS.SEQUENCE.bytes + asn1LengthPrefixed( nodes.reduce(into: Array(), { partialResult, node in + partialResult += encode(node) + })) + } + } + + /// Calculates and returns the ASN.1 length Prefix for a chunk of data + private static func asn1LengthPrefix(_ bytes:[UInt8]) -> [UInt8] { + if bytes.count >= 0x80 { + var lengthAsBytes = withUnsafeBytes(of: bytes.count.bigEndian, Array.init) + while lengthAsBytes.first == 0 { lengthAsBytes.removeFirst() } + return [(0x80 + UInt8(lengthAsBytes.count))] + lengthAsBytes + } else { + return [UInt8(bytes.count)] + } + } + + /// Returns the provided bytes with the appropriate ASN.1 length prefix prepended + private static func asn1LengthPrefixed(_ bytes:[UInt8]) -> [UInt8] { + asn1LengthPrefix(bytes) + bytes + } + } +} diff --git a/Sources/LibP2PCrypto/PEM/ASN1/ASN1Scanner.swift b/Sources/LibP2PCrypto/PEM/ASN1/ASN1Scanner.swift new file mode 100644 index 0000000..2dd820e --- /dev/null +++ b/Sources/LibP2PCrypto/PEM/ASN1/ASN1Scanner.swift @@ -0,0 +1,113 @@ +// +// ASN1Scanner.swift +// +// +// Created by Brandon Toms on 5/28/22. +// + +import Foundation + + +/// Simple data scanner that consumes bytes from a raw data and keeps an updated position. +internal 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.. 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 + } +} + +internal extension Data { + + /// Returns the first byte of the current data + var firstByte: UInt8 { + var byte: UInt8 = 0 + copyBytes(to: &byte, count: MemoryLayout.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) + } +} From 7b7c4ab20e967d339f97d37384aedab3241158e6 Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 5 Jun 2022 23:00:20 -0700 Subject: [PATCH 04/52] swift algorithms ChunksOfCountCollection --- .../PEM/Utilities/Collection+chunks.swift | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 Sources/LibP2PCrypto/PEM/Utilities/Collection+chunks.swift diff --git a/Sources/LibP2PCrypto/PEM/Utilities/Collection+chunks.swift b/Sources/LibP2PCrypto/PEM/Utilities/Collection+chunks.swift new file mode 100644 index 0000000..2368ab5 --- /dev/null +++ b/Sources/LibP2PCrypto/PEM/Utilities/Collection+chunks.swift @@ -0,0 +1,120 @@ +// +// Collection+chunks.swift +// +// +// Swift-Algorithms +// + +// MARK: Chunks of Collection (used in exporting PEM strings) +public struct ChunksOfCountCollection { + public typealias Element = Base.SubSequence + + @usableFromInline + internal let base: Base + + @usableFromInline + internal let chunkCount: Int + + @usableFromInline + internal var endOfFirstChunk: Base.Index + + /// Creates a view instance that presents the elements of `base` in + /// `SubSequence` chunks of the given count. + /// + /// - Complexity: O(*n*), because the start index is pre-computed. + @inlinable + internal init(_base: Base, _chunkCount: Int) { + self.base = _base + self.chunkCount = _chunkCount + + // Compute the start index upfront in order to make start index a O(1) + // lookup. + self.endOfFirstChunk = _base.index( + _base.startIndex, offsetBy: _chunkCount, + limitedBy: _base.endIndex + ) ?? _base.endIndex + } +} + +extension Collection { + /// Returns a `ChunksOfCountCollection` view presenting the elements in + /// chunks with count of the given count parameter. + /// + /// - Parameter count: The size of the chunks. If the `count` parameter is + /// evenly divided by the count of the base `Collection` all the chunks will + /// have the count equals to size. Otherwise, the last chunk will contain + /// the remaining elements. + /// + /// let c = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + /// print(c.chunks(ofCount: 5).map(Array.init)) + /// // [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]] + /// + /// print(c.chunks(ofCount: 3).map(Array.init)) + /// // [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]] + /// + /// - Complexity: O(*n*), because the start index is pre-computed. + @inlinable + public func chunks(ofCount count: Int) -> ChunksOfCountCollection { + precondition(count > 0, "Cannot chunk with count <= 0!") + return ChunksOfCountCollection(_base: self, _chunkCount: count) + } +} + +extension ChunksOfCountCollection: Collection { + public struct Index { + @usableFromInline + internal let baseRange: Range + + @inlinable + internal init(_baseRange: Range) { + self.baseRange = _baseRange + } + } + + /// - Complexity: O(1) + @inlinable + public var startIndex: Index { + Index(_baseRange: base.startIndex.. Element { + precondition(i != endIndex, "Index out of range") + return base[i.baseRange] + } + + @inlinable + public func index(after i: Index) -> Index { + precondition(i != endIndex, "Advancing past end index") + let baseIdx = base.index( + i.baseRange.upperBound, offsetBy: chunkCount, + limitedBy: base.endIndex + ) ?? base.endIndex + return Index(_baseRange: i.baseRange.upperBound.. Bool { + lhs.baseRange.lowerBound == rhs.baseRange.lowerBound + } + + @inlinable + public static func < (lhs: ChunksOfCountCollection.Index, + rhs: ChunksOfCountCollection.Index) -> Bool { + lhs.baseRange.lowerBound < rhs.baseRange.lowerBound + } +} + +extension ChunksOfCountCollection.Index: Hashable where Base.Index: Hashable {} + +extension ChunksOfCountCollection: LazySequenceProtocol, LazyCollectionProtocol + where Base: LazySequenceProtocol {} From b98b5e203864a59b41cc316db7031fbb929ebb93 Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 5 Jun 2022 23:01:16 -0700 Subject: [PATCH 05/52] DER Encodable, Decodable and Codable --- Sources/LibP2PCrypto/PEM/DER.swift | 199 +++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 Sources/LibP2PCrypto/PEM/DER.swift diff --git a/Sources/LibP2PCrypto/PEM/DER.swift b/Sources/LibP2PCrypto/PEM/DER.swift new file mode 100644 index 0000000..93873b1 --- /dev/null +++ b/Sources/LibP2PCrypto/PEM/DER.swift @@ -0,0 +1,199 @@ +// +// DER.swift +// +// +// Created by Brandon Toms on 5/28/22. +// + +import Foundation + +/// Conform to this protocol if your type can be instantiated from a ASN1 DER representation +public protocol DERDecodable { + /// The keys ASN1 object identifier (ex: RSA --> rsaEncryption --> [0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01]) + static var primaryObjectIdentifier:Array { get } + /// The keys ASN1 object identifier (ex: RSA --> rsaEncryption --> [0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01]) + static var secondaryObjectIdentifier:Array? { get } + /// Instantiates an instance of your Public Key when given a DER representation of your Public Key + init(publicDER: Array) throws + /// Instantiates an instance of your Private Key when given a DER representation of your Private Key + init(privateDER: Array) throws + /// Instantiates a DERDecodable Key from a PEM string + init(pem: String, password: String?, asType:Key.Type) throws + /// Instantiates a DERDecodable Key from ut8 decoded PEM data + init(pem: Data, password: String?, asType:Key.Type) throws +} + +public extension DERDecodable { + /// Instantiates a DERDecodable Key from a PEM string + /// - Parameters: + /// - pem: The PEM file to import + /// - password: A password to use to decrypt an encrypted PEM file + /// - asType: The underlying DERDecodable Key Type (ex: RSA.self) + init(pem: String, password: String? = nil, asType:Key.Type = Key.self) throws { + try self.init(pem: Data(pem.utf8), password: password, asType: Key.self) + } + + /// Instantiates a DERDecodable Key from ut8 decoded PEM data + /// - Parameters: + /// - pem: The PEM file to import + /// - password: A password to use to decrypt an encrypted PEM file + /// - asType: The underlying DERDecodable Key Type (ex: RSA.self) + init(pem: Data, password: String? = nil, asType:Key.Type = Key.self) throws { + let (type, bytes) = try PEM.pemToData(pem.bytes) + + if password != nil { + guard type == .encryptedPrivateKey else { throw PEM.Error.invalidParameters } + } + + switch type { + case .publicRSAKeyDER: + // Ensure the objectIdentifier is rsaEncryption + try self.init(publicDER: bytes) + case .privateRSAKeyDER: + // Ensure the objectIdentifier is rsaEncryption + try self.init(privateDER: bytes) + case .publicKey: + let der = try PEM.decodePublicKeyPEM(Data(bytes), expectedPrimaryObjectIdentifier: Key.primaryObjectIdentifier, expectedSecondaryObjectIdentifier: Key.secondaryObjectIdentifier) + try self.init(publicDER: der) + case .privateKey, .ecPrivateKey: + let der = try PEM.decodePrivateKeyPEM(Data(bytes), expectedPrimaryObjectIdentifier: Key.primaryObjectIdentifier, expectedSecondaryObjectIdentifier: Key.secondaryObjectIdentifier) + try self.init(privateDER: der) + case .encryptedPrivateKey: + // Decrypt the encrypted PEM and attempt to instantiate it again... + + // Ensure we were provided a password + guard let password = password else { throw PEM.Error.invalidParameters } + + // Parse out Encryption Strategy and CipherText + let decryptionStategy = try PEM.decodeEncryptedPEM(Data(bytes)) // RSA.decodeEncryptedPEM(Data(bytes)) + + // Derive Encryption Key from Password + let key = try decryptionStategy.pbkdfAlgorithm.deriveKey(password: password, ofLength: decryptionStategy.cipherAlgorithm.desiredKeyLength) + + // Decrypt CipherText + let decryptedPEM = try decryptionStategy.cipherAlgorithm.decrypt(bytes: decryptionStategy.ciphertext, withKey: key) + + // Proceed with the unencrypted PEM (can public PEM keys be encrypted as well, wouldn't really make sense but idk if we should support it)? + let der = try PEM.decodePrivateKeyPEM(Data(decryptedPEM), expectedPrimaryObjectIdentifier: Key.primaryObjectIdentifier, expectedSecondaryObjectIdentifier: Key.secondaryObjectIdentifier) + try self.init(privateDER: der) + } + } +} + +/// Conform to this protocol if your type can be described in an ASN1 DER representation +public protocol DEREncodable { + /// The keys ASN1 object identifier (ex: RSA --> rsaEncryption --> [0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01]) + static var primaryObjectIdentifier:Array { get } + /// The keys ASN1 object identifier (ex: RSA --> null --> nil) + static var secondaryObjectIdentifier:Array? { get } + + func publicKeyDER() throws -> Array + func privateKeyDER() throws -> Array + + /// PublicKey PEM Export Functions + func exportPublicKeyPEM(withHeaderAndFooter:Bool) throws -> Array + func exportPublicKeyPEMString(withHeaderAndFooter:Bool) throws -> String + + /// PrivateKey PEM Export Functions + func exportPrivateKeyPEM(withHeaderAndFooter:Bool) throws -> Array + func exportPrivateKeyPEMString(withHeaderAndFooter:Bool) throws -> String +} + +public extension DEREncodable { + func exportPublicKeyPEM(withHeaderAndFooter:Bool = true) throws -> Array { + let publicDER = try self.publicKeyDER() + let asnNodes:ASN1.Node = .sequence(nodes: [ + .sequence(nodes: [ + .objectIdentifier(data: Data(Self.primaryObjectIdentifier)), + .null + ]), + .bitString(data: Data( publicDER )) + ]) + + let base64String = ASN1.Encoder.encode(asnNodes).toBase64() + let bodyString = base64String.chunks(ofCount: 64).joined(separator: "\n") + let bodyUTF8Bytes = bodyString.bytes + + if withHeaderAndFooter { + let header = PEM.PEMType.publicKey.headerBytes + [0x0a] + let footer = [0x0a] + PEM.PEMType.publicKey.footerBytes + + return header + bodyUTF8Bytes + footer + } else { + return bodyUTF8Bytes + } + } + + func exportPublicKeyPEMString(withHeaderAndFooter:Bool = true) throws -> String { + let publicPEMData = try exportPublicKeyPEM(withHeaderAndFooter: withHeaderAndFooter) + guard let pemAsString = String(data: Data(publicPEMData), encoding: .utf8) else { + throw PEM.Error.encodingError + } + return pemAsString + } + + func exportPrivateKeyPEM(withHeaderAndFooter:Bool = true) throws -> Array { + let privateDER = try self.privateKeyDER() + let asnNodes:ASN1.Node = .sequence(nodes: [ + .integer(data: Data(hex: "0x00")), + .sequence(nodes: [ + .objectIdentifier(data: Data(Self.primaryObjectIdentifier)), + .null + ]), + .octetString(data: Data( privateDER )) + ]) + + let base64String = ASN1.Encoder.encode(asnNodes).toBase64() + let bodyString = base64String.chunks(ofCount: 64).joined(separator: "\n") + let bodyUTF8Bytes = bodyString.bytes + + if withHeaderAndFooter { + let header = PEM.PEMType.privateKey.headerBytes + [0x0a] + let footer = [0x0a] + PEM.PEMType.privateKey.footerBytes + + return header + bodyUTF8Bytes + footer + } else { + return bodyUTF8Bytes + } + } + + func exportPrivateKeyPEMString(withHeaderAndFooter:Bool = true) throws -> String { + let privatePEMData = try exportPrivateKeyPEM(withHeaderAndFooter: withHeaderAndFooter) + guard let pemAsString = String(data: Data(privatePEMData), encoding: .utf8) else { + throw PEM.Error.encodingError + } + return pemAsString + } +} + +/// Conform to this protocol if your type can both be instantiated and expressed by an ASN1 DER representation. +public protocol DERCodable: DERDecodable, DEREncodable { } + +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)) + } +} From a5039607e91c3d4a4416897f8ad366a3311bec7b Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 5 Jun 2022 23:01:56 -0700 Subject: [PATCH 06/52] PEM Decoding / Encoding --- Sources/LibP2PCrypto/PEM/PEM.swift | 478 +++++++++++++++++++++++++++++ 1 file changed, 478 insertions(+) create mode 100644 Sources/LibP2PCrypto/PEM/PEM.swift diff --git a/Sources/LibP2PCrypto/PEM/PEM.swift b/Sources/LibP2PCrypto/PEM/PEM.swift new file mode 100644 index 0000000..6b21184 --- /dev/null +++ b/Sources/LibP2PCrypto/PEM/PEM.swift @@ -0,0 +1,478 @@ +// +// PEM.swift +// +// +// Created by Brandon Toms on 5/28/22. +// + +import Foundation +import CryptoSwift + +struct PEM { + + public enum Error: Swift.Error { + /// An error occured while encoding the PEM file + case encodingError + /// An error occured while decoding the PEM file + case decodingError + /// Encountered an unsupported PEM type + case unsupportedPEMType + /// Encountered an invalid/unexpected PEM format + case invalidPEMFormat(String? = nil) + /// Encountered an invalid/unexpected PEM header string/delimiter + case invalidPEMHeader + /// Encountered an invalid/unexpected PEM footer string/delimiter + case invalidPEMFooter + /// Encountered a invalid/unexpected parameters while attempting to decode a PEM file + case invalidParameters + /// Encountered an unsupported Cipher algorithm while attempting to decrypt an encrypted PEM file + case unsupportedCipherAlgorithm([UInt8]) + /// Encountered an unsupported Password Derivation algorithm while attempting to decrypt an encrypted PEM file + case unsupportedPBKDFAlgorithm([UInt8]) + /// The instiating types objectIdentifier does not match that of the PEM file + case objectIdentifierMismatch(got:[UInt8], expected:[UInt8]) + } + + // MARK: Add support for additional PEM types here + + /// General PEM Classification + internal enum PEMType { + // Direct DER Exports for RSA Keys (special case) + case publicRSAKeyDER + case privateRSAKeyDER + + // Generale PEM Headers + case publicKey + case privateKey + case encryptedPrivateKey + case ecPrivateKey + + // Others + //case certificate + + init(headerBytes: ArraySlice) throws { + guard headerBytes.count > 10 else { throw PEM.Error.unsupportedPEMType } + let bytes = headerBytes.dropFirst(5).dropLast(5) + switch bytes { + //"BEGIN RSA PUBLIC KEY" + case [0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x52, 0x53, 0x41, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x20, 0x4b, 0x45, 0x59]: + self = .publicRSAKeyDER + + //"BEGIN RSA PRIVATE KEY" + case [0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x52, 0x53, 0x41, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59]: + self = .privateRSAKeyDER + + //"BEGIN PUBLIC KEY" + case [0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x20, 0x4b, 0x45, 0x59]: + self = .publicKey + + //"BEGIN PRIVATE KEY" + case [0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59]: + self = .privateKey + + //"BEGIN ENCRYPTED PRIVATE KEY" + case [0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x45, 0x44, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59]: + self = .encryptedPrivateKey + + case [0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x45, 0x43, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59]: + self = .ecPrivateKey + + default: + print("Unsupported PEM Type: \(Data(bytes).toHexString())") + throw PEM.Error.unsupportedPEMType + } + } + + /// This PEM type's header string (expressed as the utf8 decoded byte representation) + var headerBytes:Array { + switch self { + case .publicRSAKeyDER: + return "-----BEGIN RSA PUBLIC KEY-----".bytes + case .privateRSAKeyDER: + return "-----BEGIN RSA PRIVATE KEY-----".bytes + case .publicKey: + return "-----BEGIN PUBLIC KEY-----".bytes + case .privateKey: + return "-----BEGIN PRIVATE KEY-----".bytes + case .encryptedPrivateKey: + return "-----BEGIN ENCRYPTED PRIVATE KEY-----".bytes + case .ecPrivateKey: + return "-----BEGIN EC PRIVATE KEY-----".bytes + } + } + + /// This PEM type's footer string (expressed as the utf8 decoded byte representation) + var footerBytes:Array { + switch self { + case .publicRSAKeyDER: + return "-----END RSA PUBLIC KEY-----".bytes + case .privateRSAKeyDER: + return "-----END RSA PRIVATE KEY-----".bytes + case .publicKey: + return "-----END PUBLIC KEY-----".bytes + case .privateKey: + return "-----END PRIVATE KEY-----".bytes + case .encryptedPrivateKey: + return "-----END ENCRYPTED PRIVATE KEY-----".bytes + case .ecPrivateKey: + return "-----END EC PRIVATE KEY-----".bytes + } + } + } + + /// Converts UTF8 Encoding of PEM file into a PEMType and the base64 decoded key data + /// - Parameter data: The `UTF8` encoding of the PEM file + /// - Returns: A tuple containing the PEMType, and the actual base64 decoded PEM data (with the headers and footers removed). + internal static func pemToData(_ data:Array) throws -> (type: PEMType, bytes: Array) { + let fiveDashes = ArraySlice(repeating: 0x2D, count: 5) // "-----".bytes.toHexString() + let chunks = data.split(separator: 0x0a) // 0x0a == "\n" `new line` char + guard chunks.count > 2 else { throw PEM.Error.invalidPEMFormat("expected at least 3 chunks, a header, body and footer, but got \(chunks.count)") } + + // Enforce a valid PEM header + guard let header = chunks.first, + header.count > 10, + header.prefix(5) == fiveDashes, + header.suffix(5) == fiveDashes else { + throw PEM.Error.invalidPEMHeader + } + + // Enforce a valid PEM footer + guard let footer = chunks.last, + footer.count > 10, + footer.prefix(5) == fiveDashes, + footer.suffix(5) == fiveDashes else { + throw PEM.Error.invalidPEMFooter + } + + // Attempt to classify the PEMType based on the header + // + // - Note: This just gives us a general idea of what direction to head in. Headers that don't match the underlying data will end up throwing an Error later + let pemType:PEMType = try PEMType(headerBytes: header) + + guard let base64 = String(data: Data(chunks[1.., expectedSecondaryObjectIdentifier:Array?) throws -> Array { + let asn = try ASN1.Decoder.decode(data: pem) + + print("PublicKey") + print(asn) + + // Enforce the above ASN1 Structure + guard case .sequence(let sequence) = asn else { throw Error.invalidPEMFormat("PublicKey::No top level sequence for PublicKey PEM") } + guard sequence.count == 2 else { throw Error.invalidPEMFormat("PublicKey::Top level sequnce should contain two nodes but we got \(sequence.count) isntead") } + guard case .sequence(let params) = sequence.first else { throw Error.invalidPEMFormat("PublicKey::Expected the first node of the top level to be a sequence node, but we got \(sequence.first?.description ?? "NIL") instead") } + guard params.count >= 1 else { throw Error.invalidPEMFormat("PublicKey::Expected at least one param within the secondary sequence") } + guard case .objectIdentifier(let objectID) = params.first else { throw Error.invalidPEMFormat("PublicKey::Expected first param of secondary sequence to be an objectIndentifier") } + + // Ensure the ObjectID specified in the PEM matches that of the Key.Type we're attempting to instantiate + guard objectID.bytes == expectedPrimaryObjectIdentifier else { throw Error.objectIdentifierMismatch(got: objectID.bytes, expected: expectedPrimaryObjectIdentifier) } + + // If the key supports a secondary objectIdentifier (ensure one is present and that they match) + if let expectedSecondaryObjectIdentifier = expectedSecondaryObjectIdentifier { + guard params.count >= 2 else { throw Error.invalidPEMFormat("PrivateKey::") } + guard case .objectIdentifier(let objectIDSecondary) = params[1] else { throw Error.invalidPEMFormat("PrivateKey::") } + guard objectIDSecondary.bytes == expectedSecondaryObjectIdentifier else { throw Error.objectIdentifierMismatch(got: objectIDSecondary.bytes, expected: expectedSecondaryObjectIdentifier) } + } + + guard case .bitString(let bits) = sequence.last else { throw Error.invalidPEMFormat("Expected the last element of the top level sequence to be a bitString") } + + return bits.bytes + } + + /// Decodes an ASN1 formatted Private Key into it's raw DER representation + /// - Parameters: + /// - pem: The ASN1 encoded Private Key representation + /// - expectedObjectIdentifier: The expected objectIdentifier for the particular key type + /// - Returns: The raw octetString data (Private Key DER) + internal static func decodePrivateKeyPEM(_ pem:Data, expectedPrimaryObjectIdentifier:Array, expectedSecondaryObjectIdentifier:Array?) throws -> Array { + let asn = try ASN1.Decoder.decode(data: pem) + + print("PrivateKey") + print(asn) + + // Enforce the above ASN1 Structure + guard case .sequence(let sequence) = asn else { throw Error.invalidPEMFormat("PrivateKey::Top level node is not a sequence") } + // Enforce the integer/version param as the first param in our top level sequence + guard case .integer(let integer) = sequence.first else { throw Error.invalidPEMFormat("PrivateKey::First item in top level sequence wasn't an integer") } + print("PEM Version: \(integer.bytes)") + switch integer { + case Data(hex: "0x00"): + //Proceed with standard pkcs1 private key format + return try decodePrivateKey(sequence, expectedPrimaryObjectIdentifier: expectedPrimaryObjectIdentifier, expectedSecondaryObjectIdentifier: expectedSecondaryObjectIdentifier) + case Data(hex: "0x01"): + //Proceed with EC private key format + return try decodePrivateECKey(sequence, expectedPrimaryObjectIdentifier: expectedPrimaryObjectIdentifier) + default: + throw Error.invalidPEMFormat("Unknown version identifier") + } + } + + /// Decodes a standard (RSA) Private Key PEM file + /// - Parameters: + /// - sequence: The contents of the top level ASN1 Sequence node + /// - expectedPrimaryObjectIdentifier: The expected primary object identifier key to compare the PEM contents against + /// - expectedSecondaryObjectIdentifier: The expected secondary object identifier key to compare the PEM contents against + /// - Returns: The private key bytes + /// + /// [Private key format]() + /// ``` + /// 0:d=0 hl=4 l= 630 cons: SEQUENCE + /// 4:d=1 hl=2 l= 1 prim: INTEGER :00 + /// 7:d=1 hl=2 l= 13 cons: SEQUENCE + /// 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption + /// 20:d=2 hl=2 l= 0 prim: NULL + /// 22:d=1 hl=4 l= 608 prim: OCTET STRING [HEX DUMP]:3082...AA50 + /// ``` + private static func decodePrivateKey(_ sequence:[ASN1.Node], expectedPrimaryObjectIdentifier:Array, expectedSecondaryObjectIdentifier:Array?) throws -> Array { + guard sequence.count == 3 else { throw Error.invalidPEMFormat("PrivateKey::Top level sequence doesn't contain 3 items") } + guard case .sequence(let params) = sequence[1] else { throw Error.invalidPEMFormat("PrivateKey::Second item wasn't a sequence") } + guard params.count >= 1 else { throw Error.invalidPEMFormat("PrivateKey::Second sequence contained fewer than expected parameters") } + guard case .objectIdentifier(let objectID) = params.first else { throw Error.invalidPEMFormat("PrivateKey::") } + + // Ensure the ObjectID specified in the PEM matches that of the Key.Type we're attempting to instantiate + guard objectID.bytes == expectedPrimaryObjectIdentifier else { throw Error.objectIdentifierMismatch(got: objectID.bytes, expected: expectedPrimaryObjectIdentifier) } + + // If the key supports a secondary objectIdentifier (ensure one is present and that they match) + if let expectedSecondaryObjectIdentifier = expectedSecondaryObjectIdentifier { + guard params.count >= 2 else { throw Error.invalidPEMFormat("PrivateKey::") } + guard case .objectIdentifier(let objectIDSecondary) = params[1] else { throw Error.invalidPEMFormat("PrivateKey::") } + guard objectIDSecondary.bytes == expectedSecondaryObjectIdentifier else { throw Error.objectIdentifierMismatch(got: objectIDSecondary.bytes, expected: expectedSecondaryObjectIdentifier) } + } + + guard case .octetString(let octet) = sequence[2] else { throw Error.invalidPEMFormat("PrivateKey::") } + + return octet.bytes + } + + /// Decodes an Eliptic Curve Private Key PEM that conforms to the IETF RFC5915 structure + /// - Parameters: + /// - node: The contents of the top level ASN1 Sequence node + /// - expectedPrimaryObjectIdentifier: The expected primary object identifier key to compare the PEM contents against + /// - Returns: The EC private key bytes + /// + /// [EC private key format](https://datatracker.ietf.org/doc/html/rfc5915#section-3) + /// ``` + /// ECPrivateKey ::= SEQUENCE { + /// version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + /// privateKey OCTET STRING, + /// parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + /// publicKey [1] BIT STRING OPTIONAL + /// } + /// ``` + private static func decodePrivateECKey(_ sequence:[ASN1.Node], expectedPrimaryObjectIdentifier:Array) throws -> Array { + guard sequence.count >= 2 else { throw Error.invalidPEMFormat("PrivateKey::EC::Top level sequence doesn't contain at least 2 items") } + guard case .octetString(let octet) = sequence[1] else { throw Error.invalidPEMFormat("PrivateKey::EC::Second item wasn't an octetString") } + + // Remaining parameters are optional... + if sequence.count > 2 { + guard case .objectIdentifier(let objectID) = sequence[2] else { throw Error.invalidPEMFormat("PrivateKey::EC::Missing objectIdentifier in top level sequence") } + // Ensure the ObjectID specified in the PEM matches that of the Key.Type we're attempting to instantiate + guard objectID.bytes == expectedPrimaryObjectIdentifier else { throw Error.objectIdentifierMismatch(got: objectID.bytes, expected: expectedPrimaryObjectIdentifier) } + } + + //if sequence.count > 3 { + // // Optional Public Key + // guard case .bitString(let _) = sequence[3] else { throw Error.invalidPEMFormat("PrivateKey::EC::") } + //} + + return octet.bytes + } +} + + +// MARK: Encrypted PEM + +extension PEM { + + internal struct EncryptedPEM { + let objectIdentifer:[UInt8] + let ciphertext:[UInt8] + let pbkdfAlgorithm:PBKDFAlgorithm + let cipherAlgorithm:CipherAlgorithm + } + + /// Attempts to decode an encrypted Private Key PEM, returning all of the information necessary to decrypt the encrypted PEM + /// - Parameter encryptedPEM: The raw base64 decoded PEM data + /// - Returns: An `EncryptedPEM` Struct containing the ciphertext, the pbkdf alogrithm for key derivation, the cipher algorithm for decrypting and the objectIdentifier describing the contents of this PEM data + /// + /// To decrypt an encrypted PEM Private Key... + /// 1) Strip the headers of the PEM and base64 decode the data + /// 2) Parse the data via ASN1 looking for both the pbkdf and cipher algorithms, their respective parameters (salt, iv and itterations) and the ciphertext (aka octet string)) + /// 3) Derive the encryption key using the appropriate pbkdf alogorithm, found in step 2 + /// 4) Use the encryption key to instantiate the appropriate cipher algorithm, also found in step 2 + /// 5) Decrypt the encrypted ciphertext (the contents of the octetString node) + /// 6) The decrypted octet string can now be handled like any other Private Key PEM + /// + /// ``` + /// sequence(nodes: [ + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), // PEM's ObjectIdentifier + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), // PBKDF Algorithm + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.octetString(data: 8 bytes), // SALT + /// ASN1.Parser.Node.integer(data: 2 bytes) // ITERATIONS + /// ]) + /// ]), + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), // Cipher Algorithm (ex: des-ede3-cbc) + /// ASN1.Parser.Node.octetString(data: 16 bytes) // Initial Vector (IV) + /// ]) + /// ]) + /// ]), + /// ASN1.Parser.Node.octetString(data: 640 bytes) + /// ]) + /// ``` + internal static func decodeEncryptedPEM(_ encryptedPEM:Data) throws -> EncryptedPEM { + let asn = try ASN1.Decoder.decode(data: encryptedPEM) + + guard case .sequence(let encryptedPEMWrapper) = asn else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + guard encryptedPEMWrapper.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + guard case .sequence(let encryptionInfoWrapper) = encryptedPEMWrapper.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + guard encryptionInfoWrapper.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + guard case .objectIdentifier(let objID) = encryptionInfoWrapper.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + guard case .sequence(let encryptionAlgorithmsWrapper) = encryptionInfoWrapper.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + guard encryptionAlgorithmsWrapper.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + let pbkdf = try decodePBKFD(encryptionAlgorithmsWrapper.first!) + let cipher = try decodeCipher(encryptionAlgorithmsWrapper.last!) + guard case .octetString(let octets) = encryptedPEMWrapper.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + + return EncryptedPEM(objectIdentifer: objID.bytes, ciphertext: octets.bytes, pbkdfAlgorithm: pbkdf, cipherAlgorithm: cipher) + } +} + + +// MARK: Encrypted PEM PBKDF Algorithms + +extension PEM { + // MARK: Add support for new PBKDF Algorithms here... + internal enum PBKDFAlgorithm { + case pbkdf2(salt: [UInt8], iterations: Int) + + init(objID:[UInt8], salt:[UInt8], iterations:[UInt8]) throws { + guard let iterations = Int(iterations.toHexString(), radix: 16) else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + switch objID { + case [42, 134, 72, 134, 247, 13, 1, 5, 12]: // pbkdf2 + self = .pbkdf2(salt: salt, iterations: iterations) + default: + throw Error.unsupportedPBKDFAlgorithm(objID) + } + } + + func deriveKey(password:String, ofLength keyLength:Int, usingHashVarient variant:HMAC.Variant = .sha1) throws -> [UInt8] { + switch self { + case .pbkdf2(let salt, let iterations): + return try PKCS5.PBKDF2(password: password.bytes, salt: salt, iterations: iterations, keyLength: keyLength, variant: variant).calculate() + //default: + // throw Error.invalidPEMFormat + } + } + } + + /// Decodes the PBKDF ASN1 Block in an Encrypted Private Key PEM file + /// - Parameter node: The ASN1 sequence node containing the pbkdf parameters + /// - Returns: The PBKDFAlogrithm if supported + /// + /// Expects an ASN1.Node with the following structure + /// ``` + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), //PBKDF2 //[42,134,72,134,247,13,1,5,12] + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.octetString(data: 8 bytes), //SALT + /// ASN1.Parser.Node.integer(data: 2 bytes) //ITTERATIONS + /// ]) + /// ]) + /// ``` + fileprivate static func decodePBKFD(_ node:ASN1.Node) throws -> PBKDFAlgorithm { + guard case .sequence(let wrapper) = node else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + guard wrapper.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + guard case .objectIdentifier(let objID) = wrapper.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + guard case .sequence(let params) = wrapper.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + guard params.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + guard case .octetString(let salt) = params.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + guard case .integer(let iterations) = params.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + + return try PBKDFAlgorithm(objID: objID.bytes, salt: salt.bytes, iterations: iterations.bytes) + } +} + + +// MARK: Encrypted PEM Cipher Algorithms + +extension PEM { + // MARK: Add support for new Cipher Algorithms here... + internal enum CipherAlgorithm { + case aes_128_cbc(iv:[UInt8]) + case aes_256_cbc(iv:[UInt8]) + + init(objID:[UInt8], iv:[UInt8]) throws { + switch objID { + case [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02]: // aes-128-cbc + self = .aes_128_cbc(iv: iv) + case [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2a]: // aes-256-cbc + self = .aes_256_cbc(iv: iv) + default: + throw Error.unsupportedCipherAlgorithm(objID) + } + } + + func decrypt(bytes: [UInt8], withKey key:[UInt8]) throws -> [UInt8] { + switch self { + case .aes_128_cbc(let iv): + return try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(bytes) + case .aes_256_cbc(let iv): + return try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(bytes) + //default: + //throw Error.invalidPEMFormat + } + } + + /// The key length used for this Cipher strategy + /// - Note: we need this information when deriving the key using our PBKDF strategy + var desiredKeyLength:Int { + switch self { + case .aes_128_cbc: return 16 + case .aes_256_cbc: return 32 + } + } + } + + /// Decodes the Cipher ASN1 Block in an Encrypted Private Key PEM file + /// - Parameter node: The ASN1 sequence node containing the cipher parameters + /// - Returns: The CipherAlogrithm if supported + /// + /// Expects an ASN1.Node with the following structure + /// ``` + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), //des-ede3-cbc + /// ASN1.Parser.Node.octetString(data: 16 bytes) //IV + /// ]) + /// ``` + fileprivate static func decodeCipher(_ node:ASN1.Node) throws -> CipherAlgorithm { + guard case .sequence(let params) = node else { throw Error.invalidPEMFormat("EncryptedPrivateKey::CIPHER") } + guard params.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::CIPHER") } + guard case .objectIdentifier(let objID) = params.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::CIPHER") } + guard case .octetString(let initialVector) = params.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::CIPHER") } + + return try CipherAlgorithm(objID: objID.bytes, iv: initialVector.bytes) + } +} From dcbe2cf6d3ea7c71445449ded3f4efe00fa58ae0 Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 5 Jun 2022 23:02:27 -0700 Subject: [PATCH 07/52] Old PEM parsing logic --- .../Utils/ASN1_OLD/ASN1Parser.swift | 700 ++++++++++++++++++ .../Utils/ASN1_OLD/PEM+DER/DER_OLD.swift | 126 ++++ .../Utils/ASN1_OLD/PEM+DER/PEM_OLD.swift | 525 +++++++++++++ 3 files changed, 1351 insertions(+) create mode 100644 Sources/LibP2PCrypto/Utils/ASN1_OLD/ASN1Parser.swift create mode 100644 Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/DER_OLD.swift create mode 100644 Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/PEM_OLD.swift diff --git a/Sources/LibP2PCrypto/Utils/ASN1_OLD/ASN1Parser.swift b/Sources/LibP2PCrypto/Utils/ASN1_OLD/ASN1Parser.swift new file mode 100644 index 0000000..4bfb8a1 --- /dev/null +++ b/Sources/LibP2PCrypto/Utils/ASN1_OLD/ASN1Parser.swift @@ -0,0 +1,700 @@ +//// +//// Asn1Parser.swift +//// SwiftyRSA +//// +//// Created by Lois Di Qual on 5/9/17. +//// Copyright © 2017 Scoop. All rights reserved. +//// Modified by Brandon Toms on 5/1/22 +//// +// +//import Foundation +//import Multibase +// +///// Object Identifiers +///// [6,8,42,134,72,206,61,3,1,7] -> EC Curve 256 ':prime256v1' +///// [6,5,43,129,4,0,34] -> EC Curve 384 'secp384r1' +///// [6,5,43,129,4,0,35] -> EC Curve 521 ':secp521r1' +///// [42,134,72,206,61,2,1] -> EC Pub ':id-ecPublicKey' +///// [42,134,72,206,61,3,1,7] -> EC Pub 256 ':prime256v1' +///// [43,129,4,0,34] -> EC Pub 384 ':secp384r1' +///// [43,129,4,0,35] -> EC Pub 521 ':secp521r1' +///// [6,5,43,129,4,0,10] -> EC Secp256k1 Private +// +///// 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.. 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.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:CustomStringConvertible { +// case sequence(nodes: [Node]) +// case integer(data: Data) +// case objectIdentifier(data: Data) +// case null +// case bitString(data: Data) +// case octetString(data: Data) +// +// var description: String { +// printNode(self, level: 0) +// } +// } +// +// 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 +// +//// print([firstByte].asString(base: .base16)) +// +// // 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) +// //print(Int(data.asString(base: .base16), radix: 16) ?? -1) +// return .integer(data: data) +// } +// +// // Object identifier +// if firstByte == 0x06 { +// let length = try scanner.consumeLength() +// let data = try scanner.consume(length: length) +// //print(String(data: data, encoding: .ascii)) +// //print("Object ID: [\(data.map { "\($0)" }.joined(separator: ","))]") +// 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) +//// print(data.asString(base: .base64)) +//// print() +//// print(data.bytes) +//// print() +// 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 +// } +//} +// +// +//private let Mappings:[Array:String] = [ +// [6,8,42,134,72,206,61,3,1,7]: "prime256v1", +// [6,5,43,129,4,0,34]: "secp384r1", +// [6,5,43,129,4,0,35]: "secp521r1", +// [42,134,72,206,61,2,1]: "id-ecPublicKey", +// [42,134,72,206,61,3,1,7]: "prime256v1", +// [43,129,4,0,34]: "secp384r1", +// [43,129,4,0,35]: "secp521r1", +// [6,5,43,129,4,0,10]: "secp256k1", +// [43,101,112]: "Ed25519", +// [42,134,72,134,247,13,1,1,1]: "rsaEncryption" +//] +// +///// 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 Asn1ParserECPrivate { +// +// enum ObjectIdentifier:CustomStringConvertible { +// case prime256v1 +// case secp384r1 +// case secp521r1 +// case id_ecPublicKey +// case secp256k1 +// case Ed25519 +// case rsaEncryption +// /// Encryption Tags and Ciphers +// case aes_128_cbc // The cipher used to encrypt an encrypted key // des_ede3_cbc +// case PBKDF2 //An Encrypted PEM Key that uses PBKDF2 to derive a the AES key +// case PBES2 //An Encrypted PEM Key +// case unknown(Data) +// +// init(data:Data) { +// /// Often times Object Identifiers in private keys begin with an additional 6,5 or 6,8. +// /// If the objID has this prefix, we drop the first two bytes before attempting to classify... +// let d = data.first == 6 ? data.dropFirst(2) : data +// switch d.bytes { +// case [42,134,72,206,61,2,1]: +// self = .id_ecPublicKey +// +// case [42,134,72,206,61,3,1,7]: +// self = .prime256v1 +// +// case [43,129,4,0,34]: +// self = .secp384r1 +// +// case [43,129,4,0,35]: +// self = .secp521r1 +// +// case [43,129,4,0,10]: +// self = .secp256k1 +// +// case [43,101,112]: +// self = .Ed25519 +// +// case [42,134,72,134,247,13,1,1,1]: +// self = .rsaEncryption +// +// case [96,134,72,1,101,3,4,1,2]: +// self = .aes_128_cbc +// +// case [42,134,72,134,247,13,1,5,12]: +// self = .PBKDF2 +// +// case [42,134,72,134,247,13,1,5,13]: +// self = .PBES2 +// +// default: +// print("Found an unknown Obj ID: [\(data.map { "\($0)" }.joined(separator: ","))]") +// self = .unknown(data) +// } +// } +// +// var keyType:KeyType? { +// switch self { +// case .secp256k1: +// return .secp256K1 +// case .Ed25519: +// return .ed25519 +// case .rsaEncryption: +// return .rsa +// default: //Generic EC Curves aren't supported yet... +// return nil +// } +// } +// +// var description:String { +// switch self { +// case .prime256v1: return "prime256v1" +// case .secp384r1: return "secp384r1" +// case .secp521r1: return "secp521r1" +// case .id_ecPublicKey: return "id_ecPublicKey" +// case .secp256k1: return "secp256k1" +// case .Ed25519: return "Ed25519" +// case .rsaEncryption: return "rsaEncryption" +// /// Encryption Tags and Ciphers.... +// case .PBES2: return "PBES2" +// case .PBKDF2: return "PBKDF2" +// case .aes_128_cbc: return "aes_128_cbc" +// case .unknown(let data): +// return "Unknown Obj ID: [\(data.map { "\($0)" }.joined(separator: ","))]" +// } +// } +// } +// +// /// An ASN1 node +// enum Node { +// case sequence(nodes: [Node]) +// case integer(data: Data) +// case objectIdentifier(data: ObjectIdentifier) +// 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: 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) +// } +// +// // EC Curves Cont 0 identifier (obj id) +// if firstByte == 0xa0 { +// let length = try scanner.consumeLength() +// let data = try scanner.consume(length: length) +// //print("Found an EC Curve Obj ID: [\(data.map { "\($0)" }.joined(separator: ","))]") +// return .objectIdentifier(data: ObjectIdentifier(data: data)) +// } +// +// // EC Curves Cont 1 identifier (bit string) +// if firstByte == 0xa1 { +// 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) +// //print("Found an EC Curve Bit String: [\(data.map { "\($0)" }.joined(separator: ","))]") +// return .bitString(data: data) +// } +// +// print("Unknown byte: \([firstByte].asString(base: .base16))") +// +// 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] = [] +// do { +// while !scanner.isComplete { +// let node = try parseNode(scanner: scanner) +// nodes.append(node) +// } +// } catch { +// return nodes +// } +// return nodes +// } +//} +// +//extension LibP2PCrypto.Keys { +// +// // 256 objId -> 2a8648ce3d0301 +// // 384 objId -> 2a8648ce3d0201 +// // 521 objId -> 2a8648ce3d0201 +// public struct ASN1Parts { +// let isPrivateKey:Bool +// let keyBits:Data +// let objectIdentifier:Data +// } +// +// public static func parseASN1(pemData:Data) throws -> ASN1Parts { +// let asn = try Asn1Parser.parse(data: pemData) +// +// var bitString:Data? = nil +// var objId:Data? = nil +// var isPrivate:Bool = false +// if case .sequence(let nodes) = asn { +// nodes.forEach { +// switch $0 { +// case .objectIdentifier(let data): +// if data.first == 0x2a { +// //print("Got our obj id: \(data.asString(base: .base64))") +// objId = data +// } +// case .bitString(let data): +// //print("Got our bit string: \(data.asString(base: .base64))") +// bitString = data +// case .sequence(let nodes): +// nodes.forEach { n in +// switch n { +// case .objectIdentifier(let data): +// if data.first == 0x2a { +// //print("Got our obj id: \(data.asString(base: .base64))") +// objId = data +// } +// case .bitString(let data): +// //print("Got our bit string: \(data.asString(base: .base64))") +// bitString = data +// case .octetString(let data): +// //Private Keys trigger +// bitString = data +// isPrivate = true +// default: +// return +// } +// } +// case .octetString(let data): +// //Private Keys trigger +// bitString = data +// isPrivate = true +// default: +// return +// } +// } +// } +// +// guard let id = objId, let bits = bitString else { +// throw NSError(domain: "Unsupported asn1 format", code: 0, userInfo: nil) +// } +// +// return ASN1Parts(isPrivateKey: isPrivate, keyBits: bits, objectIdentifier: id) +// +// } +// +// public static func parseASN1ECPrivate(pemData:Data) throws -> Data { +// let asn = try Asn1ParserECPrivate.parse(data: pemData) +// +// var octetString:Data? = nil +// if case .sequence(let nodes) = asn { +// nodes.forEach { +// switch $0 { +// case .sequence(let nodes): +// nodes.forEach { n in +// switch n { +// case .octetString(let data): +// octetString = data +// default: +// return +// } +// } +// case .octetString(let data): +// octetString = data +// default: +// return +// } +// } +// } else if case .octetString(let data) = asn { +// octetString = data +// } +// +// guard let bits = octetString else { +// throw NSError(domain: "Unsupported asn1 format", code: 0, userInfo: nil) +// } +// +// return bits +// } +// +// /// 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 +// public static func stripX509HeaderFromDER(keyData: Data) throws -> Data { +// +// let node: Asn1Parser.Node +// do { +// node = try Asn1Parser.parse(data: keyData) +// } catch { +// throw NSError(domain: "asn1ParsingFailed", code: 0, userInfo: nil) +// } +// +// // Ensure the raw data is an ASN1 sequence +// guard case .sequence(let nodes) = node else { +// throw NSError(domain: "invalidAsn1RootNode", code: 0, userInfo: nil) +// } +// +// // 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 NSError(domain: "invalidAsn1Structure", code: 0, userInfo: nil) +// } +//} +// +//enum ASN1Encoder { +// private static func asn1LengthPrefix(_ bytes:[UInt8]) -> [UInt8] { +// if bytes.count >= 0x80 { +// var lengthAsBytes = withUnsafeBytes(of: bytes.count.bigEndian, Array.init) +// while lengthAsBytes.first == 0 { lengthAsBytes.removeFirst() } +// return [(0x80 + UInt8(lengthAsBytes.count))] + lengthAsBytes +// } else { +// return [UInt8(bytes.count)] +// } +// } +// +// private static func asn1LengthPrefixed(_ bytes:[UInt8]) -> [UInt8] { +// asn1LengthPrefix(bytes) + bytes +// } +// +// public static func encode(_ node:Asn1Parser.Node) -> [UInt8] { +// switch node { +// case .integer(let integer): +// return [0x02] + asn1LengthPrefixed(integer.bytes) +// case .bitString(let bits): +// return [0x03] + asn1LengthPrefixed([0x00] + bits.bytes) +// case .octetString(let octet): +// return [0x04] + asn1LengthPrefixed(octet.bytes) +// case .null: +// return [0x05, 0x00] +// case .objectIdentifier(let oid): +// return [0x06] + asn1LengthPrefixed(oid.bytes) +// case .sequence(let nodes): +// return [0x30] + asn1LengthPrefixed( nodes.reduce(into: Array(), { partialResult, node in +// partialResult += encode(node) +// }) ) +// } +// } +//} +// +//fileprivate func printNode(_ node:Asn1Parser.Node, level:Int) -> String { +// var str:[String] = [] +// let prefix = String(repeating: "\t", count: level) +// switch node { +// case .integer(let int): +// str.append("\(prefix)Integer: \(int.asString(base: .base16))") +// case .bitString(let bs): +// str.append("\(prefix)BitString: \(bs.asString(base: .base16))") +// case .null: +// str.append("\(prefix)NULL") +// case .objectIdentifier(let oid): +// str.append("\(prefix)ObjectID: \(oid.asString(base: .base16))") +// case .octetString(let os): +// str.append("\(prefix)OctetString: \(os.asString(base: .base16))") +// case .sequence(let nodes): +// nodes.forEach { str.append(printNode($0, level: level + 1)) } +// } +// return str.joined(separator: "\n") +//} diff --git a/Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/DER_OLD.swift b/Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/DER_OLD.swift new file mode 100644 index 0000000..580393f --- /dev/null +++ b/Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/DER_OLD.swift @@ -0,0 +1,126 @@ +//// +//// File.swift +//// +//// +//// Created by Brandon Toms on 5/22/22. +//// +// +//import Foundation +//import Multibase +// +//extension LibP2PCrypto.Keys { +// /// Expects a PEM Public Key with the x509 header information included (object identifier) +// /// +// /// - Note: Handles RSA and EC Public Keys +// public static func importPublicDER(_ der:String) throws -> KeyPair { +// let chunks = der.split(separator: "\n") +// guard chunks.count > 3, +// let f = chunks.first, f.hasPrefix("-----BEGIN RSA PUBLIC"), +// let l = chunks.last, l.hasSuffix("-----") else { +// throw NSError(domain: "Invalid DER Format", code: 0, userInfo: nil) +// } +// +// let raw = try BaseEncoding.decode(chunks[1.. KeyPair { +// let chunks = der.split(separator: "\n") +// guard chunks.count > 3, +// let f = chunks.first, f.hasPrefix("-----BEGIN RSA PRIVATE"), +// let l = chunks.last, l.hasSuffix("-----") else { +// throw NSError(domain: "Invalid DER Format", code: 0, userInfo: nil) +// } +// +// var raw = try BaseEncoding.decode(chunks[1.. PrivKey { +//// +//// let chunks = der.split(separator: "\n") +//// guard chunks.count > 3, +//// let f = chunks.first, f.hasPrefix("-----BEGIN"), +//// let l = chunks.last, l.hasSuffix("-----") else { +//// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) +//// } +//// +//// let raw = try BaseEncoding.decode(chunks[1..? +//// //let privKey = SecKeyCreateWithData(d as CFData, attributes as CFDictionary, &error) +//// let privKey = SecKeyCreateFromData([:] as CFDictionary, d as CFData, &error) +//// +//// guard let key = privKey else { +//// +//// throw NSError(domain: "Failed to gen priv key... \(error.debugDescription)", code: 0, userInfo: nil) +//// } +//// +//// if let pubkey = try? key.extractPubKey() { +//// print("Got the pub key...") +//// print((try? pubkey.asString(base: .base16)) ?? "nil") +//// } +//// +//// print(key.attributes) +//// +//// print((try? key.rawRepresentation()) ?? "Failed to get raw rep...") +//// +//// return key +//// +//// //return try LibP2PCrypto.Keys.secKeyFrom(data: d, isPrivateKey: true, keyType: .EC(curve: .P256)) +//// } +// +// /// Appends PEM Header and Footer +// /// Base64 encodes DER PubKey +// /// MacOS -> Use +// /// iOS roll our own +// /// https://github.com/ibm-cloud-security/Swift-JWK-to-PEM +// /// https://github.com/Kitura/OpenSSL +//// private func toDER(keyPair:LibP2PCrypto.Keys.KeyPair) throws -> String { +//// +//// // 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 keyData = try keyPair.publicKey.rawRepresentation() +//// let chunks = keyData.base64EncodedString().split(intoChunksOfLength: 64) +//// +//// let pem = [ +//// "-----BEGIN \(keyPair.keyType.name)-----", +//// chunks.joined(separator: "\n"), +//// "-----END \(keyPair.keyType.name)-----" +//// ] +//// +//// return pem.joined(separator: "\n") +//// } +// +// +//} diff --git a/Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/PEM_OLD.swift b/Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/PEM_OLD.swift new file mode 100644 index 0000000..8bb8e30 --- /dev/null +++ b/Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/PEM_OLD.swift @@ -0,0 +1,525 @@ +//// +//// PEM.swift +//// +//// +//// Created by Brandon Toms on 5/22/22. +//// + +//import Foundation +//import Multibase +//import Crypto + +//extension LibP2PCrypto.Keys { +// public struct ParsedPem { +// let isPrivate:Bool +// let type:KeyPairType +// let rawKey:Data +// } +// +// /// Parse the pem file into ASN1 bits... +// /// Scan the bits for Object Identifiers and classify the key type +// /// Based on the key type... scan the bits for the key data +// /// Return a ParsedPem struct that we can use to instantiate any of our supported KeyPairTypes... +// public static func parsePem(_ pem:String) throws -> KeyPair { +// let chunks = pem.split(separator: "\n") +// guard chunks.count >= 3, +// let f = chunks.first, f.hasPrefix("-----BEGIN"), +// let l = chunks.last, l.hasSuffix("-----") else { +// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) +// } +// +// /// If its a DER re route it... +// if f.contains("-----BEGIN RSA PUBLIC") { return try LibP2PCrypto.Keys.importPublicDER(pem) } +// else if f.contains("-----BEGIN RSA PRIVATE") { return try LibP2PCrypto.Keys.importPrivateDER(pem) } +// +// let isPrivate:Bool = f.contains("PRIVATE") +// +// let rawPem = try BaseEncoding.decode(chunks[1.. KeyPair { +// var type:KeyPairType? = nil +// let asn = try Asn1ParserECPrivate.parse(data: rawPem) +// +// print("ASN1 Nodes") +// print(asn) +// print("----------") +// +// guard case .sequence(let nodes) = asn else { throw NSError(domain: "Failed to parse PEM", code: 0, userInfo: nil) } +// let ids = objIdsInSequence(nodes) +// +// if ids.contains(where: { (id) -> Bool in +// if case .rsaEncryption = id { return true } else { return false } +// }) { +// type = .RSA(bits: .B1024) //Bit length doesn't matter here, we're just broadly classifying it... +// } else if ids.contains(where: { (id) -> Bool in +// if case .secp256k1 = id { return true } else { return false } +// }) { +// type = .Secp256k1 +// } else if ids.contains(where: { (id) -> Bool in +// if case .Ed25519 = id { return true } else { return false } +// }) { +// type = .Ed25519 +// } else if ids.contains(where: { (id) -> Bool in +// switch id { +// case .prime256v1, .secp384r1, .secp521r1: return true +// default: return false +// } +// }) { +// throw NSError(domain: "No EC Key Support Yet", code: 0, userInfo: nil) +// //type = .EC(curve: .P256) //Curve bits dont matter here, we're just broadly classifying it... +// } +// +// guard let keyType = type else { throw NSError(domain: "Failed to classify key", code: 0, userInfo: nil) } +// +// guard case .sequence(let top) = asn else { +// throw NSError(domain: "Failed to parse Asn1", code: 0, userInfo: nil) +// } +// +// var rawKeyData:Data? = nil +// +// if isPrivate { +// // First Octet +// guard let octet = octetsInSequence(top).first else { +// throw NSError(domain: "Failed to extract \(keyType.name) \(isPrivate ? "Private" : "Public") key", code: 0, userInfo: nil) +// } +// rawKeyData = octet +// } else { +// // First Bit String... +// guard let bitString = bitStringsInSequence(top).first else { +// throw NSError(domain: "Failed to extract \(keyType.name) \(isPrivate ? "Private" : "Public") key", code: 0, userInfo: nil) +// } +// rawKeyData = bitString +// } +// +// // ED25519 Private Keys are wrapped in an additional octetString node, lets remove it... +// if isPrivate, case .Ed25519 = keyType, rawKeyData?.count == 34 { +// rawKeyData?.removeFirst(2) +// } +// +// guard let keyData = rawKeyData else { +// throw NSError(domain: "Failed to extract key data from asn1 nodes", code: 0, userInfo: nil) +// } +// +// //return ParsedPem(isPrivate: isPrivate, type: keyType, rawKey: keyData) +// +// // At this point we know if its a public or private key, the type of key, and the raw bits of the key. +// // We can instantiate the key, ensure it's valid, then create a return a PublicKey or PrivateKey +// switch keyType { +// case .RSA: +// if isPrivate { +// return try KeyPair(privateKey: RSAPrivateKey(rawRepresentation: keyData)) +// } else { +// return try KeyPair(publicKey: RSAPublicKey(rawRepresentation: keyData)) +// } +// case .Ed25519: +// if isPrivate { +// return try KeyPair(privateKey: Curve25519.Signing.PrivateKey(rawRepresentation: keyData)) +// } else { +// return try KeyPair(publicKey: Curve25519.Signing.PublicKey(rawRepresentation: keyData)) +// } +// case .Secp256k1: +// if isPrivate { +// return try KeyPair(privateKey: Secp256k1PrivateKey(keyData.bytes)) +// } else { +// return try KeyPair(publicKey: Secp256k1PublicKey(keyData.bytes)) +// } +// //default: +// /// - TODO: Internal Support For EC Keys (without support for marshaling) +// // throw NSError(domain: "Unsupported Key Type \(keyType.description)", code: 0, userInfo: nil) +// } +// } +//} +// +// /// Importes an Encrypted PEM Key File +// /// +// /// An ASN1 Node Tree of an Encrypted RSA PEM Key (PBKDF2 and AES_CBC_128) +// /// ``` +// /// sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //[42,134,72,134,247,13,1,5,13] +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //PBKDF2 //[42,134,72,134,247,13,1,5,12] +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 8 bytes), //SALT +// /// libp2p_crypto.Asn1Parser.Node.integer(data: 2 bytes) //ITTERATIONS +// /// ]) +// /// ]), +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //des-ede3-cbc [96,134,72,1,101,3,4,1,2] +// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 16 bytes) //IV +// /// ]) +// /// ]) +// /// ]), +// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 640 bytes) +// /// ]) +// /// ``` +// static func parseEncryptedPem(_ pem:String, password:String) throws -> KeyPair { +// let chunks = pem.split(separator: "\n") +// guard chunks.count >= 3, +// let f = chunks.first, f.hasPrefix("-----BEGIN ENCRYPTED"), +// let l = chunks.last, l.hasSuffix("-----") else { +// throw NSError(domain: "Invalid Encrypted PEM Format", code: 0, userInfo: nil) +// } +// +// let isPrivate:Bool = f.contains("PRIVATE") +// +// let rawPem = try BaseEncoding.decode(chunks[1.. 100 { +// ciphertextData = $0 +// } else { +// saltData = $0 +// } +// } +// +// /// There should be only one integer, the itteration count... +// itterationsData = integersInSequence(nodes).first +// +// guard let salt = saltData, let iv = ivData, let itterations = itterationsData, let ciphertext = ciphertextData else { +// throw NSError(domain: "Failed to parse our pcks#8 key", code: 0, userInfo: nil) +// } +// +// // Attempt to derive the aes encryption key from the password and salt +// // PBKDF2-SHA1 +// guard let key = PBKDF2.SHA1(password: password, salt: salt, keyByteCount: iv.count, rounds: itterations) else { +// throw NSError(domain: "Failed to derive key from password and salt", code: 0, userInfo: nil) +// } +// +// //print("Key 1 -> \(key.asString(base: .base16))") +// +// //Create our CBC AES Cipher +// let aes = try LibP2PCrypto.AES.createKey(key: key, iv: iv) +// //let aes = try AES(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: .noPadding) +// +// // GCM Doesn't work on OPENSSL Encrypted PEM Files but I saw mention of it in libp2p-crypto-js so perhaps we'll need it later... +// //let aes = try AES(key: key.bytes, blockMode: GCM(iv: iv.bytes, mode: .detached), padding: .noPadding) +// +// let decryptedKey = try aes.decrypt(ciphertext.bytes) +// +// // At this point we have regular unencrypted PEM data rep of a key, lets parse it... +// return try self.parsePem(decryptedKey, isPrivate: isPrivate) +// } +// +// /// Traverses a Node tree and returns all instances of integers +// private static func integersInSequence(_ nodes:[Asn1ParserECPrivate.Node]) -> [Int] { +// var integers:[Int?] = [] +// +// nodes.forEach { +// if case .integer(let data) = $0 { integers.append(Int(data.asString(base: .base16), radix: 16)) } +// else if case .sequence(let nodes) = $0 { +// return integers.append(contentsOf: integersInSequence(nodes) ) +// } +// } +// +// return integers.compactMap { $0 } +// } +// +// /// Traverses a Node tree and returns all instances of bitStrings +// private static func bitStringsInSequence(_ nodes:[Asn1ParserECPrivate.Node]) -> [Data] { +// var bitString:[Data] = [] +// +// nodes.forEach { +// if case .bitString(let data) = $0 { bitString.append(data) } +// else if case .sequence(let nodes) = $0 { +// return bitString.append(contentsOf: bitStringsInSequence(nodes) ) +// } +// } +// +// return bitString +// } +// +// /// Traverses a Node tree and returns all instances of bitStrings +// private static func octetsInSequence(_ nodes:[Asn1ParserECPrivate.Node]) -> [Data] { +// var octets:[Data] = [] +// +// nodes.forEach { +// if case .octetString(let data) = $0 { octets.append(data) } +// else if case .sequence(let nodes) = $0 { +// return octets.append(contentsOf: octetsInSequence(nodes) ) +// } +// } +// +// return octets +// } +// +// /// Traverses a Node tree and returns all instances of objectIds +// private static func objIdsInSequence(_ nodes:[Asn1ParserECPrivate.Node]) -> [Asn1ParserECPrivate.ObjectIdentifier] { +// var objs:[Asn1ParserECPrivate.ObjectIdentifier] = [] +// +// nodes.forEach { +// if case .objectIdentifier(let id) = $0 { objs.append(id) } +// else if case .sequence(let nodes) = $0 { +// return objs.append(contentsOf: objIdsInSequence(nodes) ) +// } +// } +// +// return objs +// } +// +// /// Expects a PEM Public Key with the x509 header information included (object identifier) +// /// +// /// - Note: Handles RSA Public Keys +// public static func importPublicPem(_ pem:String) throws -> CommonPublicKey { +// let chunks = pem.split(separator: "\n") +// guard chunks.count > 3, +// let f = chunks.first, f.hasPrefix("-----BEGIN"), +// let l = chunks.last, l.hasSuffix("-----") else { +// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) +// } +// +// let raw = try BaseEncoding.decode(chunks[1.. Data { +//// let chunks = pem.split(separator: "\n") +//// guard chunks.count > 3, +//// let f = chunks.first, f.hasPrefix("-----BEGIN"), +//// let l = chunks.last, l.hasSuffix("-----") else { +//// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) +//// } +//// +//// //print("Attempting to decode: \(chunks[1.. CommonPrivateKey { +// let chunks = pem.split(separator: "\n") +// guard chunks.count > 3, +// let f = chunks.first, f.hasPrefix("-----BEGIN PRIVATE"), +// let l = chunks.last, l.hasSuffix("-----") else { +// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) +// } +// +// //print("Attempting to decode: \(chunks[1.. PrivKey { +//// let chunks = pem.split(separator: "\n") +//// guard chunks.count > 3, +//// let f = chunks.first, f.hasPrefix("-----BEGIN PRIVATE"), +//// let l = chunks.last, l.hasSuffix("-----") else { +//// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) +//// } +//// +//// //print("Attempting to decode: \(chunks[1.. PubKey { +//// var pubKey:Data? = nil +//// switch keyType { +//// case .ECDSA(curve: .P256): +//// pubKey = try P256.Signing.PublicKey(pemRepresentation: pem).rawRepresentation +//// case .ECDSA(curve: .P384): +//// pubKey = try P384.Signing.PublicKey(pemRepresentation: pem).rawRepresentation +//// case .ECDSA(curve: .P521): +//// pubKey = try P521.Signing.PublicKey(pemRepresentation: pem).rawRepresentation +//// default: +//// print("Unsupported KeyType") +//// } +//// +//// guard let pubKeyData = pubKey else { +//// throw NSError(domain: "Unable to parse PEM into Public Key", code: 0, userInfo: nil) +//// } +//// +//// let attributes: [String:Any] = [ +//// kSecAttrKeyType as String: keyType.secKey, +//// kSecAttrKeyClass as String: kSecAttrKeyClassPublic, +//// kSecAttrKeySizeInBits as String: keyType.bits, +//// kSecAttrIsPermanent as String: false +//// ] +//// +//// return try LibP2PCrypto.Keys.secKeyFrom(data: pubKeyData, attributes: attributes) +//// } +// +//// public static func initPrivKeyFromPem(_ pem:String, keyType:LibP2PCrypto.Keys.KeyPairType) throws -> PubKey { +//// var pubKey:Data? = nil +//// switch keyType { +//// case .ECDSA(curve: .P256): +//// pubKey = try P256.Signing.PrivateKey(pemRepresentation: pem).rawRepresentation +//// case .ECDSA(curve: .P384): +//// pubKey = try P384.Signing.PrivateKey(pemRepresentation: pem).rawRepresentation +//// case .ECDSA(curve: .P521): +//// pubKey = try P521.Signing.PrivateKey(pemRepresentation: pem).rawRepresentation +//// default: +//// print("Unsupported KeyType") +//// } +//// +//// guard let pubKeyData = pubKey else { +//// throw NSError(domain: "Unable to parse PEM into Private Key", code: 0, userInfo: nil) +//// } +//// +//// let attributes: [String:Any] = [ +//// kSecAttrKeyType as String: keyType.secKey, +//// kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, +//// kSecAttrKeySizeInBits as String: keyType.bits, +//// kSecAttrIsPermanent as String: false +//// ] +//// +//// return try LibP2PCrypto.Keys.secKeyFrom(data: pubKeyData, attributes: attributes) +//// } +// +// +//// public static func importPem(_ str:String) throws -> KeyPair { +//// +//// let pemData = str.data(using: .utf8) +//// +//// } +// +//// public static func fromPEM(_ str:String, keyType:LibP2PCrypto.Keys.KeyPairType) throws -> SecKey { +//// +//// guard str.hasPrefix("-----BEGIN"), str.hasSuffix("-----") else { throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) } +//// let chunks = str.split(separator: "\n") +//// guard chunks.count > 3 else { throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) } +//// //print(chunks) +//// print("Attempting to decode: \(chunks[1..? +////// let key = SecItemImport(raw.data as CFData, nil, nil, nil, .pemArmour, nil, nil, out) +////// print(key) +////// print(out) +//// let attributesRSAPriv: [String:Any] = [ +//// kSecAttrKeyType as String: kSecAttrKeyTypeRSA, +//// kSecAttrKeyClass as String: kSecAttrKeyClassPublic, +//// kSecAttrKeySizeInBits as String: keyType.bits, +//// kSecAttrIsPermanent as String: false +//// ] +//// +//// var error:Unmanaged? = nil +//// guard let secKey = SecKeyCreateWithData(key as CFData, attributesRSAPriv as CFDictionary, &error) else { +//// //guard let secKey = SecKeyCreateFromData(keyType.params! as CFDictionary, key as CFData, &error) else { +//// throw NSError(domain: "Error constructing SecKey from raw key data: \(error.debugDescription)", code: 0, userInfo: nil) +//// } +//// +//// return secKey +//// } +//} From b71603804114080212c96fec56da3ccdfdc13fe2 Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 5 Jun 2022 23:03:12 -0700 Subject: [PATCH 08/52] Signature fixture test --- Tests/LibP2PCryptoTests/pem.swift | 181 ++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) diff --git a/Tests/LibP2PCryptoTests/pem.swift b/Tests/LibP2PCryptoTests/pem.swift index 49dae78..1d506f4 100644 --- a/Tests/LibP2PCryptoTests/pem.swift +++ b/Tests/LibP2PCryptoTests/pem.swift @@ -583,3 +583,184 @@ struct TestPEMKeys { -----END CERTIFICATE----- """ } + + + +//struct TestFixtures { +// struct Fixture { +// let publicPEM:String +// let privatePEM:String +// let rawMessage:String +// let encryptedMessage:[String:String] +// let signedMessages:[String:String] +// let publicMarshaled:String +// let privateMarshaled:String +// } +// +// static let RSA_1024 = Fixture( +// publicPEM: """ +// +//""", +// privatePEM: """ +//-----BEGIN PRIVATE KEY----- +//MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANSRvSiXv+gtFt9s +//upxbjfG0l2HvFD5V/nsNa2QSl5+Vnl9RMg0P6zUCVMC/rc2x9RfcYn+n7mOGeXfP +//B5Mqvt7mFoxmo4loBFIqkbE4HDPUrduG8lb6LNfBSvA9tyaSICW+QCyOPWHBGk0P +//y382i4X6E7ActAI++RfxgttTOhmvAgMBAAECgYAyjMnf+l5ft0FGNpQWFMunnBuX +//5YP54vdWifVs4eL+x1TXM/bkFlIH1BsVjz+kt9oiJ32g/+1364W9URVrEPI8nk5i +//Id40q3Qiozvn4ceWtSoCGmuxIbdRqL1JJn5e8Zfzs7E8KZimYu00t2qcidFDUsEC +//biCqT14UNcbpwsOpkQJBAPxMogs3OnkgCWlptZckjg+srwxnXIkzDhSO+WaKl2Dm +//DvSMnB2Ws64EDu2dP+HLiuoyqG/ZqRabdQqIsIrkLpkCQQDXr+wYGoOiL26PrAew +//z49aH/wQZq8fBM2yuwvR+ZDRraQ0otQV1aRwffqlI+IfYowJvyPX+EC/ftcff0qa +//6R+HAkAQZlrSJ9DhNrfl5j0rifDCDBOE1uMo9+yeYXzMsY2NeubV9p3fPoCHezQN +//Nf+FCdoJxykzvA5Fre05thDjtllhAkEAgdsf2M81y1KlTQi0xKXiV8+D8dfwvUsm +//EOJ+Vlfb8fGKOEqER/UNgNDIM96ryFuLll6m1ONZEDHskMERiLysRwJAawkNDlqe +//sIjqrfR2luw+TLHkMI0T6pTY9s+79F9VVV/V13v2qtTpXw1eu7Sw+oDBpJoocz/h +//+YzU+CyyzO+qUA== +//-----END PRIVATE KEY----- +//""", +// rawMessage: "Hello RSA Signatures!", +// encryptedMessage: [ +// "algid:encrypt:RSA:raw": "N2T56NKkKAFdCytLP9zT0Iu9N0KNKkflB6vsNl6G+nkY/102laZLSbNZbdkzsOYSIml30ZaQSPS76aBuAYttlnCNEckgwmaS2IpHnFcUUFa/MOf+LJRcDXvkp+NoAmF0QFUhQ+VPfdineUrzOkL+xUi4hY614su6VdfPVmtJeog=", +// "algid:encrypt:RSA:PKCS1": "uliKMjgMn54C/WmwagE0dHFrEKw9civz9YYkHS+KKdlqVeCf9qKrFoSHlpA1Mq4JFg0WmpLWaMxgBaD+1CrE4Y+k26+wa4JtffLbyabYrxJkNQ5Am99KnoZO8rLEp2VumxGcsWWseMgSqrlO9KTesD8sJGFCMiz6aSFieedjAu4=" +// ], +// signedMessages: [ +// "algid:sign:RSA:raw" : "zpIDplKEdLvsHopjwoC36mQ3SRg2mZe/0RPP3DaDMnlSDLneoGwzR/L4oR/PTxD34wW7edQV4z5MrFSbmK4a7d+fwvNRQtwYlw/L04GTQyH8G6LhFUKL+++0jdPOMuMXADT8Yfrna6QHti2kqcUE4WSXHe6yY8xZZ6SHEDK71zg=", +// "algid:sign:RSA:digest-PKCS1v15" : "s64/o2jeSm9OsTwlBuwJXOkJQPLoT300ZnMPDwfAdKsVFq8vR0uUDgkKYGnaogRu66QTWHfjSPcO2RUKV23141GM6Tng3zv3WGQm2Eg663n+9tYpsV5hCussJAcAwuGHoZwFV79alpNZkFyHEjya189zPeT1K3FbZJniL0ykTuk=", +// "algid:sign:RSA:digest-PKCS1v15:SHA1" : "zIqv0mqhlDl0pf/Z5cRuZSP8oskOJhwluNI9EJRBC8b3RXlPlj2BzZyNbN0Mys3joVlfEiw4YsKYKFWN3SwGSwsYfcfeWpDJ5vJF3s32JkXnfHLdspTeapeVYDSy4MS8mNkVbYB6pQFBNK6scfzUFY7pLPKzUJ1MCnRmwpc0MbU=", +// "algid:sign:RSA:digest-PKCS1v15:SHA224" : "TS9eVlAFagKSmHtSdjunj3hgqQY5Zu7agjeYPvChB+jPgoqw/H3QwdzA4deZgcmsE1BooCgK9/1iekEWU/tjilVVrkhB5Kq5YxAWA7+IBo5pYFbmsAvP4ka+Oq1urfAYQbzTAuFyEXbdfXQATotElZFHwWjlTvZyk/IFfEawqtg=", +// "algid:sign:RSA:digest-PKCS1v15:SHA256" : "bLshLiyA9r2aow0u3+UKTSnyght7+8MuxEFzKsQrKgi9wYNwXsZEToB7jZ6+Y/hbezdIYXHwdtkHmBslAQBEGk+njsggrtWPVSDu/yU6icjEiiEd/35tVzgFejhmhj/5b8odScLrJF+6IeDl4iv9/tQZ7znOGImg5nZSik9c6dI=", +// "algid:sign:RSA:digest-PKCS1v15:SHA384" : "N810I+DcCYE7RROmKCHFl7MZl34dHkIx6Y3TxWv5g/JfvZHGRf+TwaFDjD7cGAdV+jY4wZd6mSNZvrhLgfb8t2X5JOaIiDaXt39etAywgE7OuMMYZsD596UBQFrdEu0bQIsK3+D+GcRCNYFVUUsJmYLvo/cio59IcTSRu1f3/5Y=", +// "algid:sign:RSA:digest-PKCS1v15:SHA512" : "rvrbc/LRhgGbXq1yAybMxfejAf+GHi4bcrhNKMRtg+RT3iw+Z5KLKzcSWinD9yH1j8NrL8u7EPLNDQ6EGt8y0JYSk0KqwseBpC2/zicu2HTypzFLnrNDtAw6E1A+AVOoAPkxkKf8F/ledih4xKn884USD2jO4ncyoXK4sGj0sjA=", +// "algid:sign:RSA:message-PKCS1v15:SHA1" : "BMmnNyAMr8CMYpiZJAngT1o7wDGB1+hrHBHCs5OLcM/bpzqJ8+L9hHnWBeh4hZGcIkRCnB5KFd42WwcNLUQi1EUQHvDDH9gwpT8oPWn7Y/bkflwtKl9A3R1RiobY2rafe5PlbKW+SlN8ddZ0gevt5w7Ob+vQYRLu+e5dSSxVrtY=", +// "algid:sign:RSA:message-PKCS1v15:SHA224": "Ro+Y9+TavJt18Bin3+WVVg3YOzPsIlky7LiPXkMdsh1Zq5j3CD23EehNIG2HT3QXSG2ySZuaEj0swJvJWEvcmc1lo8f0xONkgCSk8iKtRzoJ6AJe3abqwc2gNHofzUtJq/eh2ZCO/IFvXC0B4sMIf2ztJuSNRW9O8d0m8zCsHZo=", +// "algid:sign:RSA:message-PKCS1v15:SHA256": "kaqP1oUrtRPUTA5uBAcPrIDGQPAqn8uH9pHMFYumS9FwZTYlRAeCFliMuiyW79x+x+BOC6TX+mipXgWJIO1IaucyrLBKlak934SX6q71xWA74SSYlMEzalKPFpi879fvgGyY4fRypJQv5uZ3nvlvxAhyB/pX7jaV07ct9sKIQv4=", +// "algid:sign:RSA:message-PKCS1v15:SHA384": "hxsA7RjGU97s1erJAv1WTkscZk61NHv55s0BWHoJEXgda0WulbcnOQduZJWeSyxJjRh4kGztV42xOvMpo9qcovbYOI3hQJ210gbNTBKmTp9tG79ShV6lx07eceC2XZg9kYxtgkuSpurRjd2PFbkGFGhTZmqRaSQukPjSIhnxoyQ=", +// "algid:sign:RSA:message-PKCS1v15:SHA512": "r31GD74cN5wknycZDyNZdJ4HJBBLv5zMH+dmfYW98i3szDS8txdr0M8ZrmM0jLxcSpwa5461vwMBhyCOYlqY2y3HoKNolIDSANhWPufKFMcv+ob3okNDQGXOAyPKhxn/EW7X2Mz3XQlBnOA6c18KR3UnZvoW5wn9K1tpv4ueEyI=" +// ], +// publicMarshaled: "CAASogEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANSRvSiXv+gtFt9supxbjfG0l2HvFD5V/nsNa2QSl5+Vnl9RMg0P6zUCVMC/rc2x9RfcYn+n7mOGeXfPB5Mqvt7mFoxmo4loBFIqkbE4HDPUrduG8lb6LNfBSvA9tyaSICW+QCyOPWHBGk0Py382i4X6E7ActAI++RfxgttTOhmvAgMBAAE=", +// privateMarshaled: "CAAS4AQwggJcAgEAAoGBANSRvSiXv+gtFt9supxbjfG0l2HvFD5V/nsNa2QSl5+Vnl9RMg0P6zUCVMC/rc2x9RfcYn+n7mOGeXfPB5Mqvt7mFoxmo4loBFIqkbE4HDPUrduG8lb6LNfBSvA9tyaSICW+QCyOPWHBGk0Py382i4X6E7ActAI++RfxgttTOhmvAgMBAAECgYAyjMnf+l5ft0FGNpQWFMunnBuX5YP54vdWifVs4eL+x1TXM/bkFlIH1BsVjz+kt9oiJ32g/+1364W9URVrEPI8nk5iId40q3Qiozvn4ceWtSoCGmuxIbdRqL1JJn5e8Zfzs7E8KZimYu00t2qcidFDUsECbiCqT14UNcbpwsOpkQJBAPxMogs3OnkgCWlptZckjg+srwxnXIkzDhSO+WaKl2DmDvSMnB2Ws64EDu2dP+HLiuoyqG/ZqRabdQqIsIrkLpkCQQDXr+wYGoOiL26PrAewz49aH/wQZq8fBM2yuwvR+ZDRraQ0otQV1aRwffqlI+IfYowJvyPX+EC/ftcff0qa6R+HAkAQZlrSJ9DhNrfl5j0rifDCDBOE1uMo9+yeYXzMsY2NeubV9p3fPoCHezQNNf+FCdoJxykzvA5Fre05thDjtllhAkEAgdsf2M81y1KlTQi0xKXiV8+D8dfwvUsmEOJ+Vlfb8fGKOEqER/UNgNDIM96ryFuLll6m1ONZEDHskMERiLysRwJAawkNDlqesIjqrfR2luw+TLHkMI0T6pTY9s+79F9VVV/V13v2qtTpXw1eu7Sw+oDBpJoocz/h+YzU+CyyzO+qUA==" +// ) +//} + + +//func testRSAPEMImportSignAndVerify() throws { +// let expectedSignature: Array = [ +// 0x76, 0xEB, 0x7F, 0x10, 0x95, 0x40, 0xC9, 0x19, 0xE6, 0x44, 0x6F, 0xCD, 0x88, 0x83, 0x22, 0x6E, +// 0x5C, 0xE4, 0x1E, 0x87, 0xE3, 0xAF, 0x3B, 0x59, 0xB7, 0xB2, 0x89, 0xFD, 0x88, 0x37, 0xC0, 0xCE, +// 0xEA, 0x0E, 0x87, 0x06, 0x5F, 0x6E, 0xE7, 0x8C, 0xE9, 0x3F, 0xD6, 0xC3, 0xE0, 0x0B, 0x94, 0x19, +// 0xAC, 0x58, 0x2D, 0x73, 0xD3, 0x92, 0x45, 0x2C, 0x66, 0x7F, 0xB5, 0x24, 0xC6, 0xEA, 0xC6, 0xE2, +// 0x0E, 0xBB, 0x12, 0x86, 0x5B, 0xF4, 0x1D, 0x25, 0x2F, 0x68, 0x69, 0x30, 0x80, 0x4D, 0x10, 0xDF, +// 0x25, 0x5E, 0x00, 0x1D, 0x2F, 0x5F, 0x67, 0xE5, 0x4C, 0x7D, 0x1E, 0x64, 0xB2, 0x0B, 0xE8, 0x19, +// 0xE6, 0xB8, 0x62, 0xA6, 0xD1, 0x66, 0x58, 0x47, 0xAC, 0xAB, 0xAB, 0xCD, 0x26, 0x3D, 0x16, 0x52, +// 0xBF, 0x35, 0xB0, 0x21, 0xE2, 0xE3, 0x48, 0x77, 0x1E, 0x81, 0xE8, 0xCF, 0x75, 0x67, 0x64, 0x2A +// ] +// +// let message = "Hello RSA Signatures!".data(using: .utf8)! +// +// let keyPair = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.RSA_1024_PRIVATE) +// +// let secKey = try initSecKey(rawRepresentation: keyPair.privateKey!.rawRepresentation) +// +// let privateMarshaled = try keyPair.privateKey?.marshal() +// print(privateMarshaled!.asString(base: .base64Pad)) +// +// let publicMarsheled = try keyPair.marshalPublicKey() +// print(publicMarsheled.asString(base: .base64Pad)) +// +// let pemData = try secKey.extractPubKey().rawRepresentation() +// +// let pem = "-----BEGIN PUBLIC KEY-----\n" + pemData.asString(base: .base64Pad).split(intoChunksOfLength: 64).joined(separator: "\n") + "\n-----END PUBLIC KEY-----" +// +// print(pem) +// +// try sign(message: message, using: secKey)//keyPair.sign(message: message) +// +// try encrypt(data: message, with: secKey.extractPubKey()) +// +//// printHexData16BytesWide(signature.bytes) +//// print(signature.asString(base: .base64Pad)) +//// +//// XCTAssertEqual(signature.bytes, expectedSignature) +//} +// +//private func printHexData16BytesWide(_ bytes:[UInt8]) { +// print(bytes.toHexString().split(intoChunksOfLength: 32).map { $0.split(intoChunksOfLength: 2).map { "0x\($0.uppercased())" }.joined(separator: ", ") }.joined(separator: ",\n")) +//} +// +//private func initSecKey(rawRepresentation raw: Data) throws -> SecKey { +// let attributes: [String:Any] = [ +// kSecAttrKeyType as String: kSecAttrKeyTypeRSA, +// kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, +// kSecAttrKeySizeInBits as String: 1024, +// kSecAttrIsPermanent as String: false +// ] +// +// var error:Unmanaged? = nil +// guard let secKey = SecKeyCreateWithData(raw as CFData, attributes as CFDictionary, &error) else { +// throw NSError(domain: "Error constructing SecKey from raw key data: \(error.debugDescription)", code: 0, userInfo: nil) +// } +// +// return secKey +//} +// +//private func sign(message: Data, using key: SecKey) throws { +// let algorithms:[SecKeyAlgorithm] = [ +// .rsaSignatureRaw, +// //.rsaSignatureDigestPSSSHA1, +// //.rsaSignatureDigestPSSSHA224, +// //.rsaSignatureDigestPSSSHA256, +// //.rsaSignatureDigestPSSSHA384, +// //.rsaSignatureDigestPSSSHA512, +// .rsaSignatureDigestPKCS1v15Raw, +// .rsaSignatureDigestPKCS1v15SHA1, +// .rsaSignatureDigestPKCS1v15SHA224, +// .rsaSignatureDigestPKCS1v15SHA256, +// .rsaSignatureDigestPKCS1v15SHA384, +// .rsaSignatureDigestPKCS1v15SHA512, +// //.rsaSignatureMessagePSSSHA1, +// //.rsaSignatureMessagePSSSHA224, +// //.rsaSignatureMessagePSSSHA256, +// //.rsaSignatureMessagePSSSHA384, +// //.rsaSignatureMessagePSSSHA512, +// .rsaSignatureMessagePKCS1v15SHA1, +// .rsaSignatureMessagePKCS1v15SHA224, +// .rsaSignatureMessagePKCS1v15SHA256, +// .rsaSignatureMessagePKCS1v15SHA384, +// .rsaSignatureMessagePKCS1v15SHA512, +// ] +// +// for algo in algorithms { +// var error: Unmanaged? +// +// // Sign the data +// guard let signature = SecKeyCreateSignature( +// key, +// algo, +// message as CFData, +// &error) as Data? +// else { print("\"\(algo.rawValue)\": \"nil\","); continue } +// +// // Throw the error if we encountered one +// if let error = error { print("\"\(algo.rawValue)\": \"\(error.takeRetainedValue())\","); continue } +// +// // Return the signature +// print("\"\(algo.rawValue)\": \"\(signature.asString(base: .base64Pad))\",") +// } +// +//} +// +//private func encrypt(data: Data, with key:SecKey) throws { +// let algorithms:[SecKeyAlgorithm] = [ +// .rsaEncryptionRaw, +// .rsaEncryptionPKCS1 +// ] +// +// for algo in algorithms { +// var error:Unmanaged? +// guard let encryptedData = SecKeyCreateEncryptedData(key, .rsaEncryptionPKCS1, data as CFData, &error) else { +// print("\"\(algo.rawValue)\": \"\(error?.takeRetainedValue().localizedDescription ?? "nil")\","); continue +// } +// print("\"\(algo.rawValue)\": \"\((encryptedData as Data).asString(base: .base64Pad))\",") +// } +//} From ab6c9f71d1ccbb14ef973f1c682a41e338fb0357 Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 5 Jun 2022 23:04:05 -0700 Subject: [PATCH 09/52] Commented out old PEM parsing tests... --- .../LibP2PCryptoTests/LibP2PCryptoTests.swift | 2108 +++++++++-------- 1 file changed, 1123 insertions(+), 985 deletions(-) diff --git a/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift b/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift index e50d6c4..a51b2df 100644 --- a/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift +++ b/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift @@ -5,6 +5,12 @@ import Crypto import CryptoSwift import Multihash + +/// Secp - https://techdocs.akamai.com/iot-token-access-control/docs/generate-ecdsa-keys +/// JWT - https://techdocs.akamai.com/iot-token-access-control/docs/generate-jwt-ecdsa-keys +/// Fixtures - http://cryptomanager.com/tv.html +/// RSA (Sign+Verify) - https://cryptobook.nakov.com/digital-signatures/rsa-sign-verify-examples +/// PEM+DER (PKCS1&8) - https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pem final class libp2p_cryptoTests: XCTestCase { /// RSA @@ -571,8 +577,179 @@ final class libp2p_cryptoTests: XCTestCase { /// RSA Object Identifier --> 2a 86 48 86 f7 0d 01 01 01 (bit length independent, pub/priv key independent) /// ECDSA P384 --> 2a 86 48 ce 3d 02 01 - func testPemParsing() throws { - +// func testPemParsing() throws { +// +//// let pem = """ +//// -----BEGIN PUBLIC KEY----- +//// MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcZ/r0nvJyHUUstIB5BqCUJ1CC +//// Cd1nzle4bEpPQJ/S0Wn7mV2FDAeh+UcbVhZu9n+5zypYNjeZKapPqBLoT8eCK51y +//// Kpzeb8LuEm3P8PK4xN18XBrIF1GprN8IIgSdK9f5SwnemutcURrY+PlWnvj7N5s/ +//// 03RlJA3/NHVXpPW/VQIDAQAB +//// -----END PUBLIC KEY----- +//// """ +// +// let pem = """ +// -----BEGIN PRIVATE KEY----- +// MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQDp0Whyqa8KmdvK +// 0MsQGJEBzDAEHAZc0C6cr0rkb6Xwo+yB5kjZBRDORk0UXtYGE1pYt4JhUTmMzcWO +// v2xTIsdbVMQlNtput2U8kIqS1cSTkX5HxOJtCiIzntMzuR/bGPSOexkyFQ8nCUqb +// ROS7cln/ixprra2KMAKldCApN3ue2jo/JI1gyoS8sekhOASAa0ufMPpC+f70sc75 +// Y53VLnGBNM43iM/2lsK+GI2a13d6rRy86CEM/ygnh/EDlyNDxo+SQmy6GmSv/lmR +// xgWQE2dIfK504KIxFTOphPAQAr9AsmcNnCQLhbz7YTsBz8WcytHGQ0Z5pnBQJ9AV +// CX9E6DFHetvs0CNLVw1iEO06QStzHulmNEI/3P8I1TIxViuESJxSu3pSNwG1bSJZ +// +Qee24vvlz/slBzK5gZWHvdm46v7vl5z7SA+whncEtjrswd8vkJk9fI/YTUbgOC0 +// HWMdc2t/LTZDZ+LUSZ/b2n5trvdJSsOKTjEfuf0wICC08pUUk8MCAwEAAQKCAYEA +// ywve+DQCneIezHGk5cVvp2/6ApeTruXalJZlIxsRr3eq2uNwP4X2oirKpPX2RjBo +// NMKnpnsyzuOiu+Pf3hJFrTpfWzHXXm5Eq+OZcwnQO5YNY6XGO4qhSNKT9ka9Mzbo +// qRKdPrCrB+s5rryVJXKYVSInP3sDSQ2IPsYpZ6GW6Mv56PuFCpjTzElzejV7M0n5 +// 0bRmn+MZVMVUR54KYiaCywFgUzmr3yfs1cfcsKqMRywt2J58lRy/chTLZ6LILQMv +// 4V01neVJiRkTmUfIWvc1ENIFM9QJlky9AvA5ASvwTTRz8yOnxoOXE/y4OVyOePjT +// cz9eumu9N5dPuUIMmsYlXmRNaeGZPD9bIgKY5zOlfhlfZSuOLNH6EHBNr6JAgfwL +// pdP43sbg2SSNKpBZ0iSMvpyTpbigbe3OyhnFH/TyhcC2Wdf62S9/FRsvjlRPbakW +// YhKAA2kmJoydcUDO5ccEga8b7NxCdhRiczbiU2cj70pMIuOhDlGAznyxsYbtyxaB +// AoHBAPy6Cbt6y1AmuId/HYfvms6i8B+/frD1CKyn+sUDkPf81xSHV7RcNrJi1S1c +// V55I0y96HulsR+GmcAW1DF3qivWkdsd/b4mVkizd/zJm3/Dm8p8QOnNTtdWvYoEB +// VzfAhBGaR/xflSLxZh2WE8ZHQ3IcRCXV9ZFgJ7PMeTprBJXzl0lTptvrHyo9QK1v +// obLrL/KuXWS0ql1uSnJr1vtDI5uW8WU4GDENeU5b/CJHpKpjVxlGg+7pmLknxlBl +// oBnZnQKBwQDs2Ky29qZ69qnPWowKceMJ53Z6uoUeSffRZ7xuBjowpkylasEROjuL +// nyAihIYB7fd7R74CnRVYLI+O2qXfNKJ8HN+TgcWv8LudkRcnZDSvoyPEJAPyZGfr +// olRCXD3caqtarlZO7vXSAl09C6HcL2KZ8FuPIEsuO0Aw25nESMg9eVMaIC6s2eSU +// NUt6xfZw1JC0c+f0LrGuFSjxT2Dr5WKND9ageI6afuauMuosjrrOMl2g0dMcSnVz +// KrtYa7Wi1N8CgcBFnuJreUplDCWtfgEen40f+5b2yAQYr4fyOFxGxdK73jVJ/HbW +// wsh2n+9mDZg9jIZQ/+1gFGpA6V7W06dSf/hD70ihcKPDXSbloUpaEikC7jxMQWY4 +// uwjOkwAp1bq3Kxu21a+bAKHO/H1LDTrpVlxoJQ1I9wYtRDXrvBpxU2XyASbeFmNT +// FhSByFn27Ve4OD3/NrWXtoVwM5/ioX6ZvUcj55McdTWE3ddbFNACiYX9QlyOI/TY +// bhWafDCPmU9fj6kCgcEAjyQEfi9jPj2FM0RODqH1zS6OdG31tfCOTYicYQJyeKSI +// /hAezwKaqi9phHMDancfcupQ89Nr6vZDbNrIFLYC3W+1z7hGeabMPNZLYAs3rE60 +// dv4tRHlaNRbORazp1iTBmvRyRRI2js3O++3jzOb2eILDUyT5St+UU/LkY7R5EG4a +// w1df3idx9gCftXufDWHqcqT6MqFl0QgIzo5izS68+PPxitpRlR3M3Mr4rCU20Rev +// blphdF+rzAavYyj1hYuRAoHBANmxwbq+QqsJ19SmeGMvfhXj+T7fNZQFh2F0xwb2 +// rMlf4Ejsnx97KpCLUkoydqAs2q0Ws9Nkx2VEVx5KfUD7fWhgbpdnEPnQkfeXv9sD +// vZTuAoqInN1+vj1TME6EKR/6D4OtQygSNpecv23EuqEvyXWqRVsRt9Qd2B0H4k7h +// gnjREs10u7zyqBIZH7KYVgyh27WxLr859ap8cKAH6Fb+UOPtZo3sUeeume60aebn +// 4pMwXeXP+LO8NIfRXV8mgrm86g== +// -----END PRIVATE KEY----- +// """ +// +//// /// EC P256 Public Key +//// let pem = """ +//// -----BEGIN PUBLIC KEY----- +//// MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEb4nB0k8CBVnKCHVHkxuXAkSlZuO5 +//// Nsev1rzcRv5QHiJuWUKomFGadQlMSGwoDOHEDdW3ujcA6t0ADteHw6KrZg== +//// -----END PUBLIC KEY----- +//// """ +// +//// /// EC P384 Public Key +//// let pem = """ +//// -----BEGIN PUBLIC KEY----- +//// MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEBwY0l7mq7hSBEZRld5ISWfSoFsYN3wwM +//// hdD3cMU95DmYXzbqVHB4dCfsy7bexm4h9c0zs4CyTPzy3DV3vfmv1akQJIQv7l08 +//// lx/YXNeGXTN4Gr9r4rwA5GvRl1p6plPL +//// -----END PUBLIC KEY----- +//// """ +// +//// /// EC P521 Public Key +//// let pem = """ +//// -----BEGIN PUBLIC KEY----- +//// MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAp3v1UQWvSyQnkAUEBu+x/7ZrPtNJ +//// SCUk9kMvuZMyGP1idwvspALuJjzrSFFlXObjlOjxucSbWhTYF/o3nc0XzpAA3dxA +//// BYiMqH9vrVePoJMpv+DMdkUiUJ/WqHSOu9bJEi1h4fdqh5HHx4QZJY/iX/59VAi1 +//// uSbAhALvbdGFbVpkcOs= +//// -----END PUBLIC KEY----- +//// """ +// +// /// EC P256 Private Key +//// let pem = """ +//// -----BEGIN PRIVATE KEY----- +//// MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgZjQLlzempZx7YF1F +//// +MK1HWZTNgLcC1MAufb/2/YZYk6hRANCAAQwgn0PfkIHiZ/K+3zA//CoDqU2PqDc +//// aA3U5R68jmlZQITvMyBlMJl9Mjh0biIe88dAfRKeUm9FVMD2ErJ/006V +//// -----END PRIVATE KEY----- +//// """ +// +// /// PEMP384PKCS8 +//// let pem = """ +//// -----BEGIN PRIVATE KEY----- +//// MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDB7ERKhMR+mvz1NQ+oL +//// i6ZJMACOcwbUetWcNnB4Mnx3j4XuhpkkHEW8E1+rXyjZ3UmhZANiAASYH+emlyXM +//// kBSFJl0BiopDVuIIR47M4pLl00YNnuu/Rp5VHeVAHrP67i2Q92u5fk34eOSwQvkO +//// VvktWsgtzAomIam4SHqE9bhvrHy6kW6QzxlERHTL+YkXEX8c6t8VOxk= +//// -----END PRIVATE KEY----- +//// """ +// +// let chunks = pem.split(separator: "\n") +// guard chunks.count > 3, +// let f = chunks.first, f.hasPrefix("-----BEGIN"), +// let l = chunks.last, l.hasSuffix("-----") else { +// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) +// } +// +// //print("Attempting to decode: \(chunks[1.. 3, - let f = chunks.first, f.hasPrefix("-----BEGIN"), - let l = chunks.last, l.hasSuffix("-----") else { - throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) - } - - //print("Attempting to decode: \(chunks[1.. 32 { - privKeyData.removeFirst() - } - - print(privKeyData.count) - - let privKey = try Curve25519.Signing.PrivateKey(rawRepresentation: privKeyData.bytes) - - print(privKey) - - XCTAssertEqual("CM3Nzttt7KmXG9qDEYys++oQ9G749jqrbRRs92BUzpA=", privKey.publicKey.rawRepresentation.asString(base: .base64Pad)) - - } - - func testED25519PemImport_Private() throws { - let pem = """ - -----BEGIN PRIVATE KEY----- - MC4CAQAwBQYDK2VwBCIEIOkK9EOHRqD5QueUrMZbia55UWpokoFpWco4r2GnRVZ+ - -----END PRIVATE KEY----- - """ - - let keyPair = try LibP2PCrypto.Keys.parsePem(pem) - - print(keyPair) - XCTAssert(keyPair.keyType == .ed25519) - XCTAssertNotNil(keyPair.privateKey) - XCTAssertEqual(keyPair.publicKey.asString(base: .base64Pad), "CM3Nzttt7KmXG9qDEYys++oQ9G749jqrbRRs92BUzpA=") - } - - - func testSecp256k1PemImport_Public_Manual() throws { - let pem = """ - -----BEGIN PUBLIC KEY----- - MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzw - xDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== - -----END PUBLIC KEY----- - """ - - let data = try pemToData(pem) - - let asn = try Asn1ParserECPrivate.parse(data: data) - - print(asn) - -// sequence(nodes: [ -// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 7 bytes), :id-ecPublicKey -// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 5 bytes) :secp256k1 -// ]), -// libp2p_crypto.Asn1Parser.Node.bitString(data: 65 bytes) -// ]) - - guard case .sequence(let top) = asn, case .bitString(let pubKeyData) = top.last else { - return XCTFail("Failed to extract our Public Key bit/octet string") - } - - let pubKey = try Secp256k1PublicKey(pubKeyData.bytes) - - print(pubKey) - - print(pubKey.rawPublicKey.asString(base: .base64Pad)) - } - - func testSecp256k1PemImport_Public() throws { - let pem = """ - -----BEGIN PUBLIC KEY----- - MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzw - xDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== - -----END PUBLIC KEY----- - """ - - let keyPair = try LibP2PCrypto.Keys.parsePem(pem) - - print(keyPair) - XCTAssert(keyPair.keyType == .secp256k1) - XCTAssertNil(keyPair.privateKey) - print(keyPair.attributes() ?? "NIL") - } - - func testSecp256k1PemImport_Private_Manual() throws { - let pem = """ - -----BEGIN EC PRIVATE KEY----- - MHQCAQEEIJmbpwD3mZhlEtiGzmgropJ/nSewc8UPyBE9wib742saoAcGBSuBBAAK - oUQDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwf - X7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== - -----END EC PRIVATE KEY----- - """ - - let data = try pemToData(pem) - - let asn = try Asn1ParserECPrivate.parse(data: data) - - print(asn) - -// sequence(nodes: [ -// libp2p_crypto.Asn1ParserECPrivate.Node.integer(data: 1 bytes), -// libp2p_crypto.Asn1ParserECPrivate.Node.octetString(data: 32 bytes), // private key data -// libp2p_crypto.Asn1ParserECPrivate.Node.objectIdentifier(data: 7 bytes), :secp256k1 -// libp2p_crypto.Asn1ParserECPrivate.Node.bitString(data: 67 bytes) -// ]) - - guard case .sequence(let top) = asn, case .octetString(let privKeyData) = top[1] else { - return XCTFail("Failed to extract our PrivKey bit/octet string") - } - - let privKey = try Secp256k1PrivateKey(privKeyData.bytes) - - print(privKey) - - /// Assert that we can derive the public from the private key - XCTAssertEqual("IgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w==", privKey.publicKey.rawPublicKey.asString(base: .base64Pad)) - - } - +// func testRSAOpenSSLPemImport() throws { +// +// /// Generated with +// /// openssl genpkey -algorithm RSA +// /// -pkeyopt rsa_keygen_bits:3072 +// /// -pkeyopt rsa_keygen_pubexp:65537 +// let pem = """ +// -----BEGIN PRIVATE KEY----- +// MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQDp0Whyqa8KmdvK +// 0MsQGJEBzDAEHAZc0C6cr0rkb6Xwo+yB5kjZBRDORk0UXtYGE1pYt4JhUTmMzcWO +// v2xTIsdbVMQlNtput2U8kIqS1cSTkX5HxOJtCiIzntMzuR/bGPSOexkyFQ8nCUqb +// ROS7cln/ixprra2KMAKldCApN3ue2jo/JI1gyoS8sekhOASAa0ufMPpC+f70sc75 +// Y53VLnGBNM43iM/2lsK+GI2a13d6rRy86CEM/ygnh/EDlyNDxo+SQmy6GmSv/lmR +// xgWQE2dIfK504KIxFTOphPAQAr9AsmcNnCQLhbz7YTsBz8WcytHGQ0Z5pnBQJ9AV +// CX9E6DFHetvs0CNLVw1iEO06QStzHulmNEI/3P8I1TIxViuESJxSu3pSNwG1bSJZ +// +Qee24vvlz/slBzK5gZWHvdm46v7vl5z7SA+whncEtjrswd8vkJk9fI/YTUbgOC0 +// HWMdc2t/LTZDZ+LUSZ/b2n5trvdJSsOKTjEfuf0wICC08pUUk8MCAwEAAQKCAYEA +// ywve+DQCneIezHGk5cVvp2/6ApeTruXalJZlIxsRr3eq2uNwP4X2oirKpPX2RjBo +// NMKnpnsyzuOiu+Pf3hJFrTpfWzHXXm5Eq+OZcwnQO5YNY6XGO4qhSNKT9ka9Mzbo +// qRKdPrCrB+s5rryVJXKYVSInP3sDSQ2IPsYpZ6GW6Mv56PuFCpjTzElzejV7M0n5 +// 0bRmn+MZVMVUR54KYiaCywFgUzmr3yfs1cfcsKqMRywt2J58lRy/chTLZ6LILQMv +// 4V01neVJiRkTmUfIWvc1ENIFM9QJlky9AvA5ASvwTTRz8yOnxoOXE/y4OVyOePjT +// cz9eumu9N5dPuUIMmsYlXmRNaeGZPD9bIgKY5zOlfhlfZSuOLNH6EHBNr6JAgfwL +// pdP43sbg2SSNKpBZ0iSMvpyTpbigbe3OyhnFH/TyhcC2Wdf62S9/FRsvjlRPbakW +// YhKAA2kmJoydcUDO5ccEga8b7NxCdhRiczbiU2cj70pMIuOhDlGAznyxsYbtyxaB +// AoHBAPy6Cbt6y1AmuId/HYfvms6i8B+/frD1CKyn+sUDkPf81xSHV7RcNrJi1S1c +// V55I0y96HulsR+GmcAW1DF3qivWkdsd/b4mVkizd/zJm3/Dm8p8QOnNTtdWvYoEB +// VzfAhBGaR/xflSLxZh2WE8ZHQ3IcRCXV9ZFgJ7PMeTprBJXzl0lTptvrHyo9QK1v +// obLrL/KuXWS0ql1uSnJr1vtDI5uW8WU4GDENeU5b/CJHpKpjVxlGg+7pmLknxlBl +// oBnZnQKBwQDs2Ky29qZ69qnPWowKceMJ53Z6uoUeSffRZ7xuBjowpkylasEROjuL +// nyAihIYB7fd7R74CnRVYLI+O2qXfNKJ8HN+TgcWv8LudkRcnZDSvoyPEJAPyZGfr +// olRCXD3caqtarlZO7vXSAl09C6HcL2KZ8FuPIEsuO0Aw25nESMg9eVMaIC6s2eSU +// NUt6xfZw1JC0c+f0LrGuFSjxT2Dr5WKND9ageI6afuauMuosjrrOMl2g0dMcSnVz +// KrtYa7Wi1N8CgcBFnuJreUplDCWtfgEen40f+5b2yAQYr4fyOFxGxdK73jVJ/HbW +// wsh2n+9mDZg9jIZQ/+1gFGpA6V7W06dSf/hD70ihcKPDXSbloUpaEikC7jxMQWY4 +// uwjOkwAp1bq3Kxu21a+bAKHO/H1LDTrpVlxoJQ1I9wYtRDXrvBpxU2XyASbeFmNT +// FhSByFn27Ve4OD3/NrWXtoVwM5/ioX6ZvUcj55McdTWE3ddbFNACiYX9QlyOI/TY +// bhWafDCPmU9fj6kCgcEAjyQEfi9jPj2FM0RODqH1zS6OdG31tfCOTYicYQJyeKSI +// /hAezwKaqi9phHMDancfcupQ89Nr6vZDbNrIFLYC3W+1z7hGeabMPNZLYAs3rE60 +// dv4tRHlaNRbORazp1iTBmvRyRRI2js3O++3jzOb2eILDUyT5St+UU/LkY7R5EG4a +// w1df3idx9gCftXufDWHqcqT6MqFl0QgIzo5izS68+PPxitpRlR3M3Mr4rCU20Rev +// blphdF+rzAavYyj1hYuRAoHBANmxwbq+QqsJ19SmeGMvfhXj+T7fNZQFh2F0xwb2 +// rMlf4Ejsnx97KpCLUkoydqAs2q0Ws9Nkx2VEVx5KfUD7fWhgbpdnEPnQkfeXv9sD +// vZTuAoqInN1+vj1TME6EKR/6D4OtQygSNpecv23EuqEvyXWqRVsRt9Qd2B0H4k7h +// gnjREs10u7zyqBIZH7KYVgyh27WxLr859ap8cKAH6Fb+UOPtZo3sUeeume60aebn +// 4pMwXeXP+LO8NIfRXV8mgrm86g== +// -----END PRIVATE KEY----- +// """ +// +// /// Import PEM directly +// let key = try LibP2PCrypto.Keys.importPrivatePem(pem) +// +// /// Let the parsePem method determine the format and handle it accordingly +// let keyPair = try LibP2PCrypto.Keys.parsePem(pem) +// +// print(key) +// print(keyPair) +// +// XCTAssertEqual(key.rawRepresentation, keyPair.privateKey?.rawRepresentation) +// XCTAssertEqual(try key.derivePublicKey().rawRepresentation, keyPair.publicKey.data) +// XCTAssert(keyPair.keyType == .rsa) +// XCTAssertEqual(keyPair.attributes()?.size, 3072) +// XCTAssertNotNil(keyPair.privateKey) +// } +// +// // Manual PEM import process +// func testED25519PemImport_Public_Manual() throws { +// let pem = """ +// -----BEGIN PUBLIC KEY----- +// MCowBQYDK2VwAyEACM3Nzttt7KmXG9qDEYys++oQ9G749jqrbRRs92BUzpA= +// -----END PUBLIC KEY----- +// """ +// +// let data = try pemToData(pem) +// +// let asn = try Asn1Parser.parse(data: data) +// +// print(asn) +// +// guard case .sequence(let top) = asn, case .bitString(let pubKeyData) = top.last else { +// return XCTFail("Failed to extract our PubKey bit string") +// } +// +// let pubKey = try Curve25519.Signing.PublicKey(rawRepresentation: pubKeyData.bytes) +// +// print(pubKey) +// +// print(pubKey.rawRepresentation.asString(base: .base64Pad)) +// +// /// Ensure that we reached the same results using both methods +// XCTAssertEqual(pubKey.rawRepresentation, try LibP2PCrypto.Keys.parsePem(pem).publicKey.data) +// } +// +// func testED25519PemImport_Public() throws { +// let pem = """ +// -----BEGIN PUBLIC KEY----- +// MCowBQYDK2VwAyEACM3Nzttt7KmXG9qDEYys++oQ9G749jqrbRRs92BUzpA= +// -----END PUBLIC KEY----- +// """ +// +// let keyPair = try LibP2PCrypto.Keys.parsePem(pem) +// +// print(keyPair) +// XCTAssert(keyPair.keyType == .ed25519) +// XCTAssertNil(keyPair.privateKey) +// } +// +// +// /// This document defines what that is for Ed25519 private keys: +// /// https://tools.ietf.org/html/draft-ietf-curdle-pkix-10 +// /// +// /// What it says is that inside the OCTET STRING is another OCTET STRING for the private key data. The ASN.1 tag for OCTET STRING is 0x04, and the length of that string is 32 bytes (0x20 in hex). +// /// So in the above string the leading 0420 is the OCTET STRING tag and length. The remaining 32 bytes are the key itself. +// func testED25519PemImport_Private_Manual() throws { +// let pem = """ +// -----BEGIN PRIVATE KEY----- +// MC4CAQAwBQYDK2VwBCIEIOkK9EOHRqD5QueUrMZbia55UWpokoFpWco4r2GnRVZ+ +// -----END PRIVATE KEY----- +// """ +// +// let data = try pemToData(pem) +// +// let asn = try Asn1ParserECPrivate.parse(data: data) +// +// print(asn) +// +//// sequence(nodes: [ +//// libp2p_crypto.Asn1Parser.Node.integer(data: 1 bytes), +//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 3 bytes)] +//// ), +//// libp2p_crypto.Asn1Parser.Node.octetString(data: 34 bytes) <- This is actually another octetString +//// ]) +// +// guard case .sequence(let top) = asn, case .octetString(var privKeyData) = top.last else { +// return XCTFail("Failed to extract our PrivKey bit string") +// } +// +// while privKeyData.count > 32 { +// privKeyData.removeFirst() +// } +// +// print(privKeyData.count) +// +// let privKey = try Curve25519.Signing.PrivateKey(rawRepresentation: privKeyData.bytes) +// +// print(privKey) +// +// XCTAssertEqual("CM3Nzttt7KmXG9qDEYys++oQ9G749jqrbRRs92BUzpA=", privKey.publicKey.rawRepresentation.asString(base: .base64Pad)) +// +// } +// +// func testED25519PemImport_Private() throws { +// let pem = """ +// -----BEGIN PRIVATE KEY----- +// MC4CAQAwBQYDK2VwBCIEIOkK9EOHRqD5QueUrMZbia55UWpokoFpWco4r2GnRVZ+ +// -----END PRIVATE KEY----- +// """ +// +// let keyPair = try LibP2PCrypto.Keys.parsePem(pem) +// +// print(keyPair) +// XCTAssert(keyPair.keyType == .ed25519) +// XCTAssertNotNil(keyPair.privateKey) +// XCTAssertEqual(keyPair.publicKey.asString(base: .base64Pad), "CM3Nzttt7KmXG9qDEYys++oQ9G749jqrbRRs92BUzpA=") +// } +// +// +// func testSecp256k1PemImport_Public_Manual() throws { +// let pem = """ +// -----BEGIN PUBLIC KEY----- +// MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzw +// xDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== +// -----END PUBLIC KEY----- +// """ +// +// let data = try pemToData(pem) +// +// let asn = try Asn1ParserECPrivate.parse(data: data) +// +// print(asn) +// +//// sequence(nodes: [ +//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 7 bytes), :id-ecPublicKey +//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 5 bytes) :secp256k1 +//// ]), +//// libp2p_crypto.Asn1Parser.Node.bitString(data: 65 bytes) +//// ]) +// +// guard case .sequence(let top) = asn, case .bitString(let pubKeyData) = top.last else { +// return XCTFail("Failed to extract our Public Key bit/octet string") +// } +// +// let pubKey = try Secp256k1PublicKey(pubKeyData.bytes) +// +// print(pubKey) +// +// print(pubKey.rawPublicKey.asString(base: .base64Pad)) +// } +// +// func testSecp256k1PemImport_Public() throws { +// let pem = """ +// -----BEGIN PUBLIC KEY----- +// MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzw +// xDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== +// -----END PUBLIC KEY----- +// """ +// +// let keyPair = try LibP2PCrypto.Keys.parsePem(pem) +// +// print(keyPair) +// XCTAssert(keyPair.keyType == .secp256k1) +// XCTAssertNil(keyPair.privateKey) +// print(keyPair.attributes() ?? "NIL") +// } +// +// func testSecp256k1PemImport_Private_Manual() throws { +// let pem = """ +// -----BEGIN EC PRIVATE KEY----- +// MHQCAQEEIJmbpwD3mZhlEtiGzmgropJ/nSewc8UPyBE9wib742saoAcGBSuBBAAK +// oUQDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwf +// X7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== +// -----END EC PRIVATE KEY----- +// """ +// +// let data = try pemToData(pem) +// +// let asn = try Asn1ParserECPrivate.parse(data: data) +// +// print(asn) +// +//// sequence(nodes: [ +//// libp2p_crypto.Asn1ParserECPrivate.Node.integer(data: 1 bytes), +//// libp2p_crypto.Asn1ParserECPrivate.Node.octetString(data: 32 bytes), // private key data +//// libp2p_crypto.Asn1ParserECPrivate.Node.objectIdentifier(data: 7 bytes), :secp256k1 +//// libp2p_crypto.Asn1ParserECPrivate.Node.bitString(data: 67 bytes) +//// ]) +// +// guard case .sequence(let top) = asn, case .octetString(let privKeyData) = top[1] else { +// return XCTFail("Failed to extract our PrivKey bit/octet string") +// } +// +// let privKey = try Secp256k1PrivateKey(privKeyData.bytes) +// +// print(privKey) +// +// /// Assert that we can derive the public from the private key +// XCTAssertEqual("IgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w==", privKey.publicKey.rawPublicKey.asString(base: .base64Pad)) +// +// } +// func testSecp256k1PemImport_Private() throws { let pem = """ -----BEGIN EC PRIVATE KEY----- @@ -1365,475 +1371,476 @@ final class libp2p_cryptoTests: XCTestCase { /// 5) Decrypt the encrypted octet string /// 6) The decrypted octet string can be ASN1 parsed again for the private key octet string /// 7) This raw data can be used to instantiate a SecKey - func testRSAEncryptedPrivateKeyPem2_Manual() throws { - - // Generated with - // openssl genpkey -algorithm RSA - // -pkeyopt rsa_keygen_bits:1024 - // -pkeyopt rsa_keygen_pubexp:65537 - // -out foo.pem - let unencryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.UNENCRYPTED - - // Encrypted with - // openssl pkcs8 -in foo.pem -topk8 -v2 aes-128-cbc -passout pass:mypassword - let encryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.ENCRYPTED - - let asn = try Asn1Parser.parse(data: pemToData(encryptedPem)) - - print(asn) - -// sequence(nodes: [ -// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //[42,134,72,134,247,13,1,5,13] -// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //PBKDF2 //[42,134,72,134,247,13,1,5,12] -// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// libp2p_crypto.Asn1Parser.Node.octetString(data: 8 bytes), //SALT -// libp2p_crypto.Asn1Parser.Node.integer(data: 2 bytes) //ITTERATIONS -// ]) -// ]), -// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //des-ede3-cbc [96,134,72,1,101,3,4,1,2] -// libp2p_crypto.Asn1Parser.Node.octetString(data: 16 bytes) //IV -// ]) -// ]) -// ]), -// libp2p_crypto.Asn1Parser.Node.octetString(data: 640 bytes) -// ]) - - var saltData:Data? = nil - var ivData:Data? = nil - var itterationsData:Int? = nil - var ciphertextData:Data? = nil - - if case .sequence(let top) = asn { - if case .sequence(let top1) = top.first { - if case .sequence(let top2) = top1.last { - if case .sequence(let top3) = top2.first { - if case .sequence(let top4) = top3.last { - if case .octetString(let salt) = top4.first { - print("Found the salt: \(salt.asString(base: .base16))") - saltData = salt - } - if case .integer(let int) = top4.last { - print("Found the itterations: \(int.asString(base: .base16))") - itterationsData = Int(int.asString(base: .base16), radix: 16) - } - } - } - if case .sequence(let bottom3) = top2.last { - if case .octetString(let iv) = bottom3.last { - print("Found the IV: \(iv.asString(base: .base16))") - ivData = iv - } - } - } - } - if case .octetString(let cipherText) = top.last { - print("Found the ciphertext: \(cipherText.count)") - ciphertextData = cipherText - } - } - - // Ensure we have everything we need to proceed... - guard let salt = saltData, let iv = ivData, let itterations = itterationsData, let ciphertext = ciphertextData else { - return XCTFail("Failed to parse our pcks#8 key") - } - - // Attempt to derive the aes encryption key from the password and salt - // PBKDF2-SHA1 - guard let key = PBKDF2.SHA1(password: "mypassword", salt: salt, keyByteCount: 16, rounds: itterations) else { - return XCTFail("Failed to derive key from password and salt") - } - - // This also works, but it is incredibly slow... -// let key2 = try PKCS5.PBKDF2( -// password: Array("mypassword".utf8), -// salt: salt.bytes, -// iterations: itterations, -// keyLength: 16, /* 16 == AES-128, 32 == AES-256 */ -// variant: .sha256 -// ).calculate() - - // These should be the same - print("Key 1 -> \(key.asString(base: .base16))") - //print("Key 2 -> \(key2.asString(base: .base16))") - - //Create our CBC AES Cipher - let aes = try AES(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: .noPadding) - - // Try GCM - //let aes = try AES(key: key.bytes, blockMode: GCM(iv: iv.bytes, mode: .detached), padding: .noPadding) - - let decryptedKey = try aes.decrypt(ciphertext.bytes) - - print(decryptedKey.asString(base: .base64)) - - let deASN = try Asn1Parser.parse(data: Data(decryptedKey)) - print(deASN) - print("-----") - let unASN = try Asn1Parser.parse(data: pemToData(unencryptedPem)) - print(unASN) - - /// sequence(nodes: [ - /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ - /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), // [42,134,72,134,247,13,1,1,1] => RSA Private Key - /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ - /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ - /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), - /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ - /// libp2p_crypto.Asn1Parser.Node.octetString(data: 8 bytes), - /// libp2p_crypto.Asn1Parser.Node.integer(data: 2 bytes) - /// ]) - /// ]), - /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ - /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), - /// libp2p_crypto.Asn1Parser.Node.octetString(data: 16 bytes) - /// ]) - /// ]), - /// libp2p_crypto.Asn1Parser.Node.octetString(data: 640 bytes) - /// ]) - /// ]) - - var unencRawPrivateKeyData:Data? = nil - if case .sequence(let top) = unASN { - if case .octetString(let d) = top.last { - print("Found our unenc octetString") - unencRawPrivateKeyData = d - } - } - - var decRawPrivateKeyData:Data? = nil - if case .sequence(let top) = deASN { - if case .octetString(let d) = top.last { - print("Found our dec octetString") - decRawPrivateKeyData = d - } - } - - guard let uRawPrivKeyData = unencRawPrivateKeyData else { - return XCTFail("Failed to parse our unencrypted private pem key...") - } - - guard let dRawPrivKeyData = decRawPrivateKeyData else { - return XCTFail("Failed to parse our decrypted private pem key...") - } - - print(uRawPrivKeyData.asString(base: .base64)) - print(dRawPrivKeyData.asString(base: .base64)) - - print(dRawPrivKeyData.count) - print(uRawPrivKeyData.count) - - let og = try RSAPrivateKey(rawRepresentation: uRawPrivKeyData) - let de = try RSAPrivateKey(rawRepresentation: dRawPrivKeyData) - - print(og) - - print(de) - - XCTAssertEqual(uRawPrivKeyData, dRawPrivKeyData) - XCTAssertEqual(og, de) - - - //XCTAssertEqual(uRawPrivKeyData.bytes, decryptedKey, "Not Equal") - - } - - func testRSAEncryptedPrivateKeyPem2() throws { - - // Generated with - // openssl genpkey -algorithm RSA - // -pkeyopt rsa_keygen_bits:1024 - // -pkeyopt rsa_keygen_pubexp:65537 - // -out foo.pem - let unencryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.UNENCRYPTED - - // Encrypted with - // openssl pkcs8 -in foo.pem -topk8 -v2 aes-128-cbc -passout pass:mypassword - let encryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.ENCRYPTED - - let fromDecrypted = try LibP2PCrypto.Keys.parsePem(unencryptedPem) - let fromEncrypted = try LibP2PCrypto.Keys.parseEncryptedPem(encryptedPem, password: "mypassword") - - XCTAssertNotNil(fromDecrypted.privateKey) - XCTAssertNotNil(fromEncrypted.privateKey) - - XCTAssertTrue(fromDecrypted.keyType == .rsa) - XCTAssertTrue(fromEncrypted.keyType == .rsa) - - XCTAssertEqual(fromDecrypted.privateKey?.rawRepresentation, fromEncrypted.privateKey?.rawRepresentation) - XCTAssertEqual(fromDecrypted.publicKey.data, fromEncrypted.publicKey.data) - - let attributes = fromEncrypted.attributes() - XCTAssertEqual(attributes!.size, 1024) - XCTAssertTrue(attributes!.isPrivate) - } - - private func pemToData(_ str:String) throws -> Data { - let chunks = str.split(separator: "\n") - guard chunks.count > 2, - let f = chunks.first, f.hasPrefix("-----BEGIN"), - let l = chunks.last, l.hasSuffix("-----") else { - throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) - } - - return try BaseEncoding.decode(chunks[1..} The private key protobuf -// */ -// import: async function (privateKey, password) { -// const base64 = multibase.names.base64 -// const encryptedKey = base64.decode(privateKey) -// const cipher = ciphers.create() -// return await cipher.decrypt(encryptedKey, password) -// } -// -// function create ({ -// algorithmTagLength = 16, -// nonceLength = 12, -// keyLength = 16, -// digest = 'sha256', -// saltLength = 16, -// iterations = 32767 -// } = {}) { -// const algorithm = 'aes-128-gcm' -// -// /** -// * Decrypts the given cipher text with the provided key. The `key` should -// * be a cryptographically safe key and not a plaintext password. To use -// * a plaintext password, use `decrypt`. The options used to create -// * this decryption cipher must be the same as those used to create -// * the encryption cipher. -// * -// * @private -// * @param {Uint8Array} ciphertextAndNonce The data to decrypt -// * @param {Uint8Array} key -// * @returns {Promise} -// */ -// async function decryptWithKey (ciphertextAndNonce, key) { // eslint-disable-line require-await -// // Create Uint8Arrays of nonce, ciphertext and tag. -// const nonce = ciphertextAndNonce.slice(0, nonceLength) -// const ciphertext = ciphertextAndNonce.slice(nonceLength, ciphertextAndNonce.length - algorithmTagLength) -// const tag = ciphertextAndNonce.slice(ciphertext.length + nonceLength) -// -// // Create the cipher instance. -// const cipher = crypto.createDecipheriv(algorithm, key, nonce) -// -// // Decrypt and return result. -// cipher.setAuthTag(tag) -// return uint8ArrayConcat([cipher.update(ciphertext), cipher.final()]) -// } -// -// /** -// * Uses the provided password to derive a pbkdf2 key. The key -// * will then be used to decrypt the data. The options used to create -// * this decryption cipher must be the same as those used to create -// * the encryption cipher. -// * -// * @param {Uint8Array} data The data to decrypt -// * @param {string|Uint8Array} password A plain password -// */ -// async function decrypt (data, password) { // eslint-disable-line require-await -// // Create Uint8Arrays of salt and ciphertextAndNonce. -// const salt = data.slice(0, saltLength) -// const ciphertextAndNonce = data.slice(saltLength) -// -// if (typeof password === 'string' || password instanceof String) { -// password = uint8ArrayFromString(password) -// } -// -// // Derive the key using PBKDF2. -// const key = crypto.pbkdf2Sync(password, salt, iterations, keyLength, digest) -// -// // Decrypt and return result. -// return decryptWithKey(ciphertextAndNonce, key) -// } -// */ -// -// -// /// Private Key -// /// Raw Bytes: [1, 187, 116, 255, 157, 152, 71, 218, 87, 128, 62, 200, 148, 52, 164, 109, 237, 133, 89, 216, 240, 207, 80, 244, 60, 41, 32, 117, 184, 2, 231, 7, 9, 237, 110, 180, 86, 120, 103, 133, 84, 215, 104, 137, 101, 171, 127, 154, 54, 153, 229, 201, 46, 20, 1, 221, 211, 59, 129, 102, 129, 5, 76, 249, 30, 182] -// /// Bytes: 66 -// /// --- -// /// Public Key -// /// Raw Bytes: [0, 110, 196, 197, 185, 248, 73, 76, 67, 3, 127, 38, 67, 168, 163, 6, 20, 223, 146, 233, 198, 22, 77, 105, 120, 172, 14, 6, 95, 144, 206, 161, 48, 16, 46, 29, 26, 53, 177, 60, 132, 212, 146, 37, 203, 104, 104, 81, 129, 246, 149, 222, 98, 0, 249, 7, 134, 50, 83, 122, 75, 74, 242, 216, 234, 152, 0, 196, 255, 251, 57, 249, 20, 79, 95, 72, 156, 153, 174, 189, 153, 145, 253, 72, 69, 57, 114, 180, 179, 100, 173, 183, 100, 235, 84, 42, 66, 116, 93, 139, 64, 190, 225, 15, 90, 159, 178, 212, 204, 25, 174, 159, 36, 177, 45, 227, 230, 147, 191, 167, 141, 103, 47, 96, 183, 159, 143, 89, 155, 144, 199, 38] -// /// Bytes: 132 -// /// --- -// func testECRawRep() throws { -// let key = P521.Signing.PrivateKey() -// -// let rawPrivKey = key.rawRepresentation -// let rawPubKey = key.publicKey.rawRepresentation -// -// //print(key.x963Representation.asString(base: .base64)) -// print("Private Key") -// print("Raw Bytes: \(rawPrivKey.bytes)") -// print("Bytes: \(rawPrivKey.bytes.count)") -// print("---") -// //print(rawRep.asString(base: .base64)) -// print("Public Key") -// print("Raw Bytes: \(rawPubKey.bytes)") -// print("Bytes: \(rawPubKey.bytes.count)") -// print("---") -// -// let importedKey = try P521.Signing.PrivateKey(rawRepresentation: rawPrivKey) +// // Encrypted with +// // openssl pkcs8 -in foo.pem -topk8 -v2 aes-128-cbc -passout pass:mypassword +// let encryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.ENCRYPTED // -// print(importedKey) -// } +// let asn = try Asn1Parser.parse(data: pemToData(encryptedPem)) // -// func testImportEncryptedPemKey() throws { -// /* -// * Generated with -// * openssl genpkey -algorithm RSA -// * -pkeyopt rsa_keygen_bits:1024 -// * -pkeyopt rsa_keygen_pubexp:65537 -// * -out foo.pem -// * openssl pkcs8 -in foo.pem -topk8 -v2 des3 -passout pass:mypassword -// */ -// let pem = """ -// -----BEGIN ENCRYPTED PRIVATE KEY----- -// MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQISznrfHd+D58CAggA -// MBQGCCqGSIb3DQMHBAhx0DnnUvDiHASCAoCceplm+Cmwlgvn4hNsv6e4c/S1iA7w -// 2hU7Jt8JgRCIMWjP2FthXOAFLa2fD4g3qncYXcDAFBXNyoh25OgOwstO14YkxhDi -// wG4TeppGUt9IlyyCol6Z4WhQs1TGm5OcD5xDta+zBXsBnlgmKLD5ZXPEYB+3v/Dg -// SvM4sQz6NgkVHN52hchERsnknwSOghiK9mIBH0RZU5LgzlDy2VoBCiEPVdZ7m4F2 -// dft5e82zFS58vwDeNN/0r7fC54TyJf/8k3q94+4Hp0mseZ67LR39cvnEKuDuFROm -// kLPLekWt5R2NGdunSQlA79BkrNB1ADruO8hQOOHMO9Y3/gNPWLKk+qrfHcUni+w3 -// Ofq+rdfakHRb8D6PUmsp3wQj6fSOwOyq3S50VwP4P02gKcZ1om1RvEzTbVMyL3sh -// hZcVB3vViu3DO2/56wo29lPVTpj9bSYjw/CO5jNpPBab0B/Gv7JAR0z4Q8gn6OPy -// qf+ddyW4Kcb6QUtMrYepghDthOiS3YJV/zCNdL3gTtVs5Ku9QwQ8FeM0/5oJZPlC -// TxGuOFEJnYRWqIdByCP8mp/qXS5alSR4uoYQSd7vZG4vkhkPNSAwux/qK1IWfqiW -// 3XlZzrbD//9IzFVqGRs4nRIFq85ULK0zAR57HEKIwGyn2brEJzrxpV6xsHBp+m4w -// 6r0+PtwuWA0NauTCUzJ1biUdH8t0TgBL6YLaMjlrfU7JstH3TpcZzhJzsjfy0+zV -// NT2TO3kSzXpQ5M2VjOoHPm2fqxD/js+ThDB3QLi4+C7HqakfiTY1lYzXl9/vayt6 -// DUD29r9pYL9ErB9tYko2rat54EY7k7Ts6S5jf+8G7Zz234We1APhvqaG -// -----END ENCRYPTED PRIVATE KEY----- -// """ +// print(asn) // -// let chunks = pem.split(separator: "\n") -// guard chunks.count > 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) +//// sequence(nodes: [ +//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //[42,134,72,134,247,13,1,5,13] +//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //PBKDF2 //[42,134,72,134,247,13,1,5,12] +//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +//// libp2p_crypto.Asn1Parser.Node.octetString(data: 8 bytes), //SALT +//// libp2p_crypto.Asn1Parser.Node.integer(data: 2 bytes) //ITTERATIONS +//// ]) +//// ]), +//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //des-ede3-cbc [96,134,72,1,101,3,4,1,2] +//// libp2p_crypto.Asn1Parser.Node.octetString(data: 16 bytes) //IV +//// ]) +//// ]) +//// ]), +//// libp2p_crypto.Asn1Parser.Node.octetString(data: 640 bytes) +//// ]) +// +// var saltData:Data? = nil +// var ivData:Data? = nil +// var itterationsData:Int? = nil +// var ciphertextData:Data? = nil +// +// if case .sequence(let top) = asn { +// if case .sequence(let top1) = top.first { +// if case .sequence(let top2) = top1.last { +// if case .sequence(let top3) = top2.first { +// if case .sequence(let top4) = top3.last { +// if case .octetString(let salt) = top4.first { +// print("Found the salt: \(salt.asString(base: .base16))") +// saltData = salt +// } +// if case .integer(let int) = top4.last { +// print("Found the itterations: \(int.asString(base: .base16))") +// itterationsData = Int(int.asString(base: .base16), radix: 16) +// } +// } +// } +// if case .sequence(let bottom3) = top2.last { +// if case .octetString(let iv) = bottom3.last { +// print("Found the IV: \(iv.asString(base: .base16))") +// ivData = iv +// } +// } +// } +// } +// if case .octetString(let cipherText) = top.last { +// print("Found the ciphertext: \(cipherText.count)") +// ciphertextData = cipherText +// } // } // -// let raw = try BaseEncoding.decode(chunks[1.. \(key.asString(base: .base16))") +// //print("Key 2 -> \(key2.asString(base: .base16))") +// +// //Create our CBC AES Cipher +// let aes = try AES(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: .noPadding) +// +// // Try GCM +// //let aes = try AES(key: key.bytes, blockMode: GCM(iv: iv.bytes, mode: .detached), padding: .noPadding) +// +// let decryptedKey = try aes.decrypt(ciphertext.bytes) +// +// print(decryptedKey.asString(base: .base64)) +// +// let deASN = try Asn1Parser.parse(data: Data(decryptedKey)) +// print(deASN) +// print("-----") +// let unASN = try Asn1Parser.parse(data: pemToData(unencryptedPem)) +// print(unASN) +// +// /// sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), // [42,134,72,134,247,13,1,1,1] => RSA Private Key +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 8 bytes), +// /// libp2p_crypto.Asn1Parser.Node.integer(data: 2 bytes) +// /// ]) +// /// ]), +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), +// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 16 bytes) +// /// ]) +// /// ]), +// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 640 bytes) +// /// ]) +// /// ]) +// +// var unencRawPrivateKeyData:Data? = nil +// if case .sequence(let top) = unASN { +// if case .octetString(let d) = top.last { +// print("Found our unenc octetString") +// unencRawPrivateKeyData = d // } // } // -// if let bits = bitString { -// print("Trying to Init Encrypted RSA Key from bitString") -// let sk = try RSAPrivate(rawRepresentation: bits) -// print(sk) -// } else if let oct = oct { -// print("Trying to Init Encrypted EC Key from octetString") -// let sk = try RSAPrivate(rawRepresentation: oct) -// print(sk) +// var decRawPrivateKeyData:Data? = nil +// if case .sequence(let top) = deASN { +// if case .octetString(let d) = top.last { +// print("Found our dec octetString") +// decRawPrivateKeyData = d +// } +// } +// +// guard let uRawPrivKeyData = unencRawPrivateKeyData else { +// return XCTFail("Failed to parse our unencrypted private pem key...") +// } +// +// guard let dRawPrivKeyData = decRawPrivateKeyData else { +// return XCTFail("Failed to parse our decrypted private pem key...") // } // +// print(uRawPrivKeyData.asString(base: .base64)) +// print(dRawPrivKeyData.asString(base: .base64)) +// +// print(dRawPrivKeyData.count) +// print(uRawPrivKeyData.count) +// +// let og = try RSAPrivateKey(rawRepresentation: uRawPrivKeyData) +// let de = try RSAPrivateKey(rawRepresentation: dRawPrivKeyData) +// +// print(og) +// +// print(de) +// +// XCTAssertEqual(uRawPrivKeyData, dRawPrivKeyData) +// XCTAssertEqual(og, de) +// +// +// //XCTAssertEqual(uRawPrivKeyData.bytes, decryptedKey, "Not Equal") +// +// } +// +// func testRSAEncryptedPrivateKeyPem2() throws { +// +// // Generated with +// // openssl genpkey -algorithm RSA +// // -pkeyopt rsa_keygen_bits:1024 +// // -pkeyopt rsa_keygen_pubexp:65537 +// // -out foo.pem +// let unencryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.UNENCRYPTED +// +// // Encrypted with +// // openssl pkcs8 -in foo.pem -topk8 -v2 aes-128-cbc -passout pass:mypassword +// let encryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.ENCRYPTED +// +// let fromDecrypted = try LibP2PCrypto.Keys.parsePem(unencryptedPem) +// let fromEncrypted = try LibP2PCrypto.Keys.parseEncryptedPem(encryptedPem, password: "mypassword") +// +// XCTAssertNotNil(fromDecrypted.privateKey) +// XCTAssertNotNil(fromEncrypted.privateKey) +// +// XCTAssertTrue(fromDecrypted.keyType == .rsa) +// XCTAssertTrue(fromEncrypted.keyType == .rsa) +// +// XCTAssertEqual(fromDecrypted.privateKey?.rawRepresentation, fromEncrypted.privateKey?.rawRepresentation) +// XCTAssertEqual(fromDecrypted.publicKey.data, fromEncrypted.publicKey.data) +// +// let attributes = fromEncrypted.attributes() +// XCTAssertEqual(attributes!.size, 1024) +// XCTAssertTrue(attributes!.isPrivate) +// } +// +// private func pemToData(_ str:String) throws -> Data { +// let chunks = str.split(separator: "\n") +// guard chunks.count > 2, +// let f = chunks.first, f.hasPrefix("-----BEGIN"), +// let l = chunks.last, l.hasSuffix("-----") else { +// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) +// } +// +// return try BaseEncoding.decode(chunks[1..} The private key protobuf +//// */ +//// import: async function (privateKey, password) { +//// const base64 = multibase.names.base64 +//// const encryptedKey = base64.decode(privateKey) +//// const cipher = ciphers.create() +//// return await cipher.decrypt(encryptedKey, password) +//// } //// -//// // Now the public keys, which all fail. -//// XCTAssertThrowsError(try P256.Signing.PublicKey(pemRepresentation: pemPrivateKey)) { error in -//// XCTAssertEqual(error as? CryptoKitASN1Error, .invalidPEMDocument) -//// } -//// XCTAssertThrowsError(try P256.KeyAgreement.PublicKey(pemRepresentation: pemPrivateKey)) { error in -//// XCTAssertEqual(error as? CryptoKitASN1Error, .invalidPEMDocument) -//// } -//// XCTAssertThrowsError(try P384.Signing.PublicKey(pemRepresentation: pemPrivateKey)) { error in -//// XCTAssertEqual(error as? CryptoKitASN1Error, .invalidPEMDocument) -//// } -//// XCTAssertThrowsError(try P384.KeyAgreement.PublicKey(pemRepresentation: pemPrivateKey)) { error in -//// XCTAssertEqual(error as? CryptoKitASN1Error, .invalidPEMDocument) +//// function create ({ +//// algorithmTagLength = 16, +//// nonceLength = 12, +//// keyLength = 16, +//// digest = 'sha256', +//// saltLength = 16, +//// iterations = 32767 +//// } = {}) { +//// const algorithm = 'aes-128-gcm' +//// +//// /** +//// * Decrypts the given cipher text with the provided key. The `key` should +//// * be a cryptographically safe key and not a plaintext password. To use +//// * a plaintext password, use `decrypt`. The options used to create +//// * this decryption cipher must be the same as those used to create +//// * the encryption cipher. +//// * +//// * @private +//// * @param {Uint8Array} ciphertextAndNonce The data to decrypt +//// * @param {Uint8Array} key +//// * @returns {Promise} +//// */ +//// async function decryptWithKey (ciphertextAndNonce, key) { // eslint-disable-line require-await +//// // Create Uint8Arrays of nonce, ciphertext and tag. +//// const nonce = ciphertextAndNonce.slice(0, nonceLength) +//// const ciphertext = ciphertextAndNonce.slice(nonceLength, ciphertextAndNonce.length - algorithmTagLength) +//// const tag = ciphertextAndNonce.slice(ciphertext.length + nonceLength) +//// +//// // Create the cipher instance. +//// const cipher = crypto.createDecipheriv(algorithm, key, nonce) +//// +//// // Decrypt and return result. +//// cipher.setAuthTag(tag) +//// return uint8ArrayConcat([cipher.update(ciphertext), cipher.final()]) +//// } +//// +//// /** +//// * Uses the provided password to derive a pbkdf2 key. The key +//// * will then be used to decrypt the data. The options used to create +//// * this decryption cipher must be the same as those used to create +//// * the encryption cipher. +//// * +//// * @param {Uint8Array} data The data to decrypt +//// * @param {string|Uint8Array} password A plain password +//// */ +//// async function decrypt (data, password) { // eslint-disable-line require-await +//// // Create Uint8Arrays of salt and ciphertextAndNonce. +//// const salt = data.slice(0, saltLength) +//// const ciphertextAndNonce = data.slice(saltLength) +//// +//// if (typeof password === 'string' || password instanceof String) { +//// password = uint8ArrayFromString(password) +//// } +//// +//// // Derive the key using PBKDF2. +//// const key = crypto.pbkdf2Sync(password, salt, iterations, keyLength, digest) +//// +//// // Decrypt and return result. +//// return decryptWithKey(ciphertextAndNonce, key) +//// } +//// */ +//// +//// +//// /// Private Key +//// /// Raw Bytes: [1, 187, 116, 255, 157, 152, 71, 218, 87, 128, 62, 200, 148, 52, 164, 109, 237, 133, 89, 216, 240, 207, 80, 244, 60, 41, 32, 117, 184, 2, 231, 7, 9, 237, 110, 180, 86, 120, 103, 133, 84, 215, 104, 137, 101, 171, 127, 154, 54, 153, 229, 201, 46, 20, 1, 221, 211, 59, 129, 102, 129, 5, 76, 249, 30, 182] +//// /// Bytes: 66 +//// /// --- +//// /// Public Key +//// /// Raw Bytes: [0, 110, 196, 197, 185, 248, 73, 76, 67, 3, 127, 38, 67, 168, 163, 6, 20, 223, 146, 233, 198, 22, 77, 105, 120, 172, 14, 6, 95, 144, 206, 161, 48, 16, 46, 29, 26, 53, 177, 60, 132, 212, 146, 37, 203, 104, 104, 81, 129, 246, 149, 222, 98, 0, 249, 7, 134, 50, 83, 122, 75, 74, 242, 216, 234, 152, 0, 196, 255, 251, 57, 249, 20, 79, 95, 72, 156, 153, 174, 189, 153, 145, 253, 72, 69, 57, 114, 180, 179, 100, 173, 183, 100, 235, 84, 42, 66, 116, 93, 139, 64, 190, 225, 15, 90, 159, 178, 212, 204, 25, 174, 159, 36, 177, 45, 227, 230, 147, 191, 167, 141, 103, 47, 96, 183, 159, 143, 89, 155, 144, 199, 38] +//// /// Bytes: 132 +//// /// --- +//// func testECRawRep() throws { +//// let key = P521.Signing.PrivateKey() +//// +//// let rawPrivKey = key.rawRepresentation +//// let rawPubKey = key.publicKey.rawRepresentation +//// +//// //print(key.x963Representation.asString(base: .base64)) +//// print("Private Key") +//// print("Raw Bytes: \(rawPrivKey.bytes)") +//// print("Bytes: \(rawPrivKey.bytes.count)") +//// print("---") +//// //print(rawRep.asString(base: .base64)) +//// print("Public Key") +//// print("Raw Bytes: \(rawPubKey.bytes)") +//// print("Bytes: \(rawPubKey.bytes.count)") +//// print("---") +//// +//// let importedKey = try P521.Signing.PrivateKey(rawRepresentation: rawPrivKey) +//// +//// print(importedKey) +//// } +//// +//// func testImportEncryptedPemKey() throws { +//// /* +//// * Generated with +//// * openssl genpkey -algorithm RSA +//// * -pkeyopt rsa_keygen_bits:1024 +//// * -pkeyopt rsa_keygen_pubexp:65537 +//// * -out foo.pem +//// * openssl pkcs8 -in foo.pem -topk8 -v2 des3 -passout pass:mypassword +//// */ +//// let pem = """ +//// -----BEGIN ENCRYPTED PRIVATE KEY----- +//// MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQISznrfHd+D58CAggA +//// MBQGCCqGSIb3DQMHBAhx0DnnUvDiHASCAoCceplm+Cmwlgvn4hNsv6e4c/S1iA7w +//// 2hU7Jt8JgRCIMWjP2FthXOAFLa2fD4g3qncYXcDAFBXNyoh25OgOwstO14YkxhDi +//// wG4TeppGUt9IlyyCol6Z4WhQs1TGm5OcD5xDta+zBXsBnlgmKLD5ZXPEYB+3v/Dg +//// SvM4sQz6NgkVHN52hchERsnknwSOghiK9mIBH0RZU5LgzlDy2VoBCiEPVdZ7m4F2 +//// dft5e82zFS58vwDeNN/0r7fC54TyJf/8k3q94+4Hp0mseZ67LR39cvnEKuDuFROm +//// kLPLekWt5R2NGdunSQlA79BkrNB1ADruO8hQOOHMO9Y3/gNPWLKk+qrfHcUni+w3 +//// Ofq+rdfakHRb8D6PUmsp3wQj6fSOwOyq3S50VwP4P02gKcZ1om1RvEzTbVMyL3sh +//// hZcVB3vViu3DO2/56wo29lPVTpj9bSYjw/CO5jNpPBab0B/Gv7JAR0z4Q8gn6OPy +//// qf+ddyW4Kcb6QUtMrYepghDthOiS3YJV/zCNdL3gTtVs5Ku9QwQ8FeM0/5oJZPlC +//// TxGuOFEJnYRWqIdByCP8mp/qXS5alSR4uoYQSd7vZG4vkhkPNSAwux/qK1IWfqiW +//// 3XlZzrbD//9IzFVqGRs4nRIFq85ULK0zAR57HEKIwGyn2brEJzrxpV6xsHBp+m4w +//// 6r0+PtwuWA0NauTCUzJ1biUdH8t0TgBL6YLaMjlrfU7JstH3TpcZzhJzsjfy0+zV +//// NT2TO3kSzXpQ5M2VjOoHPm2fqxD/js+ThDB3QLi4+C7HqakfiTY1lYzXl9/vayt6 +//// DUD29r9pYL9ErB9tYko2rat54EY7k7Ts6S5jf+8G7Zz234We1APhvqaG +//// -----END ENCRYPTED PRIVATE KEY----- +//// """ +//// +//// let chunks = pem.split(separator: "\n") +//// guard chunks.count > 3, +//// let f = chunks.first, f.hasPrefix("-----BEGIN"), +//// let l = chunks.last, l.hasSuffix("-----") else { +//// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) //// } -//// XCTAssertThrowsError(try P521.Signing.PublicKey(pemRepresentation: pemPrivateKey)) { error in -//// XCTAssertEqual(error as? CryptoKitASN1Error, .invalidPEMDocument) +//// +//// let raw = try BaseEncoding.decode(chunks[1.. ec-secp256k1-pub-key.pem` func testSecp256k1_Pem_Parsing_Public() throws { - let parsed = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.SECP256k1_KeyPair.PUBLIC) + //let parsed = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.SECP256k1_KeyPair.PUBLIC) - print(parsed) - } + //print(parsed) + + //2a8648ce3d0201 + //2b8104000a + //let secp256k1Public = try Secp256k1PublicKey(pem: TestPEMKeys.SECP256k1_KeyPair.PUBLIC, asType: Secp256k1PublicKey.self) + + //print(secp256k1Public) + + //let secp256k1Private = try Secp256k1PrivateKey(pem: TestPEMKeys.SECP256k1_KeyPair.PRIVATE, asType: Secp256k1PrivateKey.self) - func testSecp256k1_Pem_Parsing_Private() throws { - let parsed = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.SECP256k1_KeyPair.PRIVATE) + //print(secp256k1Private) +// XCTAssertEqual(secp256k1Private.publicKey, secp256k1Public) + + /// 0:d=0 hl=3 l= 162 cons: SEQUENCE + /// 3:d=1 hl=2 l= 1 prim: INTEGER :01 + /// 6:d=1 hl=2 l= 44 cons: SEQUENCE + /// 8:d=2 hl=2 l= 7 prim: OBJECT :prime-field + /// 17:d=2 hl=2 l= 33 prim: INTEGER :FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F + /// 52:d=1 hl=2 l= 6 cons: SEQUENCE + /// 54:d=2 hl=2 l= 1 prim: OCTET STRING [HEX DUMP]:00 + /// 57:d=2 hl=2 l= 1 prim: OCTET STRING [HEX DUMP]:07 + /// 60:d=1 hl=2 l= 65 prim: OCTET STRING [HEX DUMP]:0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 + /// 127:d=1 hl=2 l= 33 prim: INTEGER :FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 + /// 162:d=1 hl=2 l= 1 prim: INTEGER :01 + let ecPEM = """ + -----BEGIN EC PRIVATE KEY----- + MIIBEwIBAQQgiOURdsStmumMgM2c29TlUxEdNxrQns8VPeM0sV08MtKggaUwgaIC + AQEwLAYHKoZIzj0BAQIhAP////////////////////////////////////7///wv + MAYEAQAEAQcEQQR5vmZ++dy7rFWgYpXOhwsHApv82y3OKNlZ8oFbFvgXmEg62ncm + o8RlXaT7/A4RCKj9F7RIpoVUGZxH0I/7ENS4AiEA/////////////////////rqu + 3OavSKA7v9JejNA2QUECAQGhRANCAASDsnwEULWLn8HV8iobNGNAdze/SbwbehJ3 + l+gvkHpYQ2tMD9d4NTMDKFTxPUN+w0ktADgGaPhd2flQ2dNL7nFT + -----END EC PRIVATE KEY----- + """ + let ecPEM2 = """ + -----BEGIN EC PRIVATE KEY----- + MHQCAQEEIFTQEjBp0zAIiafoD6+xwBS/kAvc4qq0BVZ1QTk//EguoAcGBSuBBAAK + oUQDQgAEmLNqAvsnenwfMz8+U5MUGb4zwhfxVBjRqn7Bqa/CCVPtsqSMfhzaE30u + OQlpl7VjL/jrZYpUv8aPRfTBSn396w== + -----END EC PRIVATE KEY----- + """ + + let ecParams = """ + -----BEGIN EC PARAMETERS----- + BgUrgQQACg== + -----END EC PARAMETERS----- + """ + + let ecPEMPrivate = """ + -----BEGIN EC PRIVATE KEY----- + MHQCAQEEINMfarC/mmrd3GKaOfl+7iXffsdg4MqMa4HY5wkBDilooAcGBSuBBAAK + oUQDQgAEJ9kHLQX2sVEh14Duq23w5af30636vUx93jVsMIDhONwwuQc2N7mv4/oY + 8oB3EPTRyh+o+6J+9qXI1VaJjvSr5Q== + -----END EC PRIVATE KEY----- + """ + let ecPEMPublic = """ + -----BEGIN PUBLIC KEY----- + MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJ9kHLQX2sVEh14Duq23w5af30636vUx9 + 3jVsMIDhONwwuQc2N7mv4/oY8oB3EPTRyh+o+6J+9qXI1VaJjvSr5Q== + -----END PUBLIC KEY----- + """ + + let pemBase64String = ecPEM2.split(separator: "\n").dropFirst().dropLast().joined() + let pemData = Data(base64Encoded: pemBase64String)! + + print(pemData.toHexString()) + + //30820113 + // 020101 + // 042088e51176c4ad9ae98c80cd9cdbd4e553111d371ad09ecf153de334b15d3c32d2a081a53081a2 + // 020101 + // 302c06072a8648ce3d0101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f + // 3006 + // 040100 + // 040107 + // 04410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 + // 022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0//364141 + // 020101 + // a144 + // 0342 + // 00 + // 0483b27c0450b58b9fc1d5f22a1b3463407737bf49bc1b7a127797e82f907a58436b4c0fd7783533032854f13d437ec3492d00380668f85dd9f950d9d34bee7153 + + + //3074 + // 020101 + // 042054d0123069d3300889a7e80fafb1c014bf900bdce2aab405567541393ffc + //482ea00706052b8104000aa1440342000498b36a02fb277a7c1f333f3e53931419be33c217f15418d1aa7ec1a9afc20953edb2a48c7e1cda137d2e39096997b5632ff8eb658a54bfc68f45f4c14a7dfdeb + + let parsed = try ASN1.Decoder.decode(data: pemData) + print(parsed) + +// if case .octetString(let rawData) = parsed { +// let edPrivate = try Curve25519.Signing.PrivateKey(rawRepresentation: rawData) +// print(edPrivate) +// } + } + +// +// func testSecp256k1_Pem_Parsing_Private() throws { +// let parsed = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.SECP256k1_KeyPair.PRIVATE) +// +// print(parsed) +// } + + func testImportSecp256k1PEM() throws { + let secp256k1Public = try Secp256k1PublicKey(pem: TestPEMKeys.SECP256k1_KeyPair.PUBLIC, asType: Secp256k1PublicKey.self) + + print(secp256k1Public) + + let secp256k1Private = try Secp256k1PrivateKey(pem: TestPEMKeys.SECP256k1_KeyPair.PRIVATE, asType: Secp256k1PrivateKey.self) + + print(secp256k1Private) } /// -----BEGIN PGP PUBLIC KEY BLOCK----- @@ -2049,29 +2187,29 @@ final class libp2p_cryptoTests: XCTestCase { ("testHMACKey", testHMACKey), ("testHMACBaseEncoded", testHMACBaseEncoded), ("testHMACVerify", testHMACVerify), - ("testPemParsing", testPemParsing), - ("testPemParsing_RSA_1024_Public", testPemParsing_RSA_1024_Public), - ("testPemParsing_RSA_1024_Public_2", testPemParsing_RSA_1024_Public_2), - ("testPemParsing_RSA_2048_Public", testPemParsing_RSA_2048_Public), - ("testPemParsing_RSA_3072_Public", testPemParsing_RSA_3072_Public), - ("testPemParsing_RSA_4096_Public", testPemParsing_RSA_4096_Public), - ("testRSAOpenSSLPemImport", testRSAOpenSSLPemImport), - ("testED25519PemImport_Public_Manual", testED25519PemImport_Public_Manual), - ("testED25519PemImport_Public", testED25519PemImport_Public), - ("testED25519PemImport_Private_Manual", testED25519PemImport_Private_Manual), - ("testED25519PemImport_Private", testED25519PemImport_Private), - ("testSecp256k1PemImport_Public_Manual", testSecp256k1PemImport_Public_Manual), - ("testSecp256k1PemImport_Public", testSecp256k1PemImport_Public), - ("testSecp256k1PemImport_Private_Manual", testSecp256k1PemImport_Private_Manual), - ("testSecp256k1PemImport_Private", testSecp256k1PemImport_Private), - ("testRSAEncryptedPrivateKeyPem2_Manual", testRSAEncryptedPrivateKeyPem2_Manual), - ("testRSAEncryptedPrivateKeyPem2", testRSAEncryptedPrivateKeyPem2), - ("testRSA_Pem_Parsing_Public", testRSA_Pem_Parsing_Public), - ("testRSA_Pem_Parsing_Private", testRSA_Pem_Parsing_Private), - ("testEd25519_Pem_Parsing_Public", testEd25519_Pem_Parsing_Public), - ("testEd25519_Pem_Parsing_Private", testEd25519_Pem_Parsing_Private), - ("testSecp256k1_Pem_Parsing_Public", testSecp256k1_Pem_Parsing_Public), - ("testSecp256k1_Pem_Parsing_Private", testSecp256k1_Pem_Parsing_Private), + //("testPemParsing", testPemParsing), + //("testPemParsing_RSA_1024_Public", testPemParsing_RSA_1024_Public), + //("testPemParsing_RSA_1024_Public_2", testPemParsing_RSA_1024_Public_2), + //("testPemParsing_RSA_2048_Public", testPemParsing_RSA_2048_Public), + //("testPemParsing_RSA_3072_Public", testPemParsing_RSA_3072_Public), + //("testPemParsing_RSA_4096_Public", testPemParsing_RSA_4096_Public), + //("testRSAOpenSSLPemImport", testRSAOpenSSLPemImport), + //("testED25519PemImport_Public_Manual", testED25519PemImport_Public_Manual), + //("testED25519PemImport_Public", testED25519PemImport_Public), + //("testED25519PemImport_Private_Manual", testED25519PemImport_Private_Manual), + //("testED25519PemImport_Private", testED25519PemImport_Private), + //("testSecp256k1PemImport_Public_Manual", testSecp256k1PemImport_Public_Manual), + //("testSecp256k1PemImport_Public", testSecp256k1PemImport_Public), + //("testSecp256k1PemImport_Private_Manual", testSecp256k1PemImport_Private_Manual), + //("testSecp256k1PemImport_Private", testSecp256k1PemImport_Private), + //("testRSAEncryptedPrivateKeyPem2_Manual", testRSAEncryptedPrivateKeyPem2_Manual), + //("testRSAEncryptedPrivateKeyPem2", testRSAEncryptedPrivateKeyPem2), + //("testRSA_Pem_Parsing_Public", testRSA_Pem_Parsing_Public), + //("testRSA_Pem_Parsing_Private", testRSA_Pem_Parsing_Private), + //("testEd25519_Pem_Parsing_Public", testEd25519_Pem_Parsing_Public), + //("testEd25519_Pem_Parsing_Private", testEd25519_Pem_Parsing_Private), + //("testSecp256k1_Pem_Parsing_Public", testSecp256k1_Pem_Parsing_Public), + //("testSecp256k1_Pem_Parsing_Private", testSecp256k1_Pem_Parsing_Private), ("testEmbeddedEd25519PublicKey", testEmbeddedEd25519PublicKey) ] } From 1066bc33a11d9f256bd534d1c809e5a7ce384bdc Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 5 Jun 2022 23:05:03 -0700 Subject: [PATCH 10/52] Removed old files --- Sources/LibP2PCrypto/Utils/ASN1Parser.swift | 700 ------------------- Sources/LibP2PCrypto/Utils/PEM+DER/DER.swift | 126 ---- Sources/LibP2PCrypto/Utils/PEM+DER/PEM.swift | 524 -------------- 3 files changed, 1350 deletions(-) delete mode 100644 Sources/LibP2PCrypto/Utils/ASN1Parser.swift delete mode 100644 Sources/LibP2PCrypto/Utils/PEM+DER/DER.swift delete mode 100644 Sources/LibP2PCrypto/Utils/PEM+DER/PEM.swift diff --git a/Sources/LibP2PCrypto/Utils/ASN1Parser.swift b/Sources/LibP2PCrypto/Utils/ASN1Parser.swift deleted file mode 100644 index c1799de..0000000 --- a/Sources/LibP2PCrypto/Utils/ASN1Parser.swift +++ /dev/null @@ -1,700 +0,0 @@ -// -// Asn1Parser.swift -// SwiftyRSA -// -// Created by Lois Di Qual on 5/9/17. -// Copyright © 2017 Scoop. All rights reserved. -// Modified by Brandon Toms on 5/1/22 -// - -import Foundation -import Multibase - -/// Object Identifiers -/// [6,8,42,134,72,206,61,3,1,7] -> EC Curve 256 ':prime256v1' -/// [6,5,43,129,4,0,34] -> EC Curve 384 'secp384r1' -/// [6,5,43,129,4,0,35] -> EC Curve 521 ':secp521r1' -/// [42,134,72,206,61,2,1] -> EC Pub ':id-ecPublicKey' -/// [42,134,72,206,61,3,1,7] -> EC Pub 256 ':prime256v1' -/// [43,129,4,0,34] -> EC Pub 384 ':secp384r1' -/// [43,129,4,0,35] -> EC Pub 521 ':secp521r1' -/// [6,5,43,129,4,0,10] -> EC Secp256k1 Private - -/// 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.. 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.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:CustomStringConvertible { - case sequence(nodes: [Node]) - case integer(data: Data) - case objectIdentifier(data: Data) - case null - case bitString(data: Data) - case octetString(data: Data) - - var description: String { - printNode(self, level: 0) - } - } - - 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 - -// print([firstByte].asString(base: .base16)) - - // 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) - //print(Int(data.asString(base: .base16), radix: 16) ?? -1) - return .integer(data: data) - } - - // Object identifier - if firstByte == 0x06 { - let length = try scanner.consumeLength() - let data = try scanner.consume(length: length) - //print(String(data: data, encoding: .ascii)) - //print("Object ID: [\(data.map { "\($0)" }.joined(separator: ","))]") - 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) -// print(data.asString(base: .base64)) -// print() -// print(data.bytes) -// print() - 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 - } -} - - -private let Mappings:[Array:String] = [ - [6,8,42,134,72,206,61,3,1,7]: "prime256v1", - [6,5,43,129,4,0,34]: "secp384r1", - [6,5,43,129,4,0,35]: "secp521r1", - [42,134,72,206,61,2,1]: "id-ecPublicKey", - [42,134,72,206,61,3,1,7]: "prime256v1", - [43,129,4,0,34]: "secp384r1", - [43,129,4,0,35]: "secp521r1", - [6,5,43,129,4,0,10]: "secp256k1", - [43,101,112]: "Ed25519", - [42,134,72,134,247,13,1,1,1]: "rsaEncryption" -] - -/// 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 Asn1ParserECPrivate { - - enum ObjectIdentifier:CustomStringConvertible { - case prime256v1 - case secp384r1 - case secp521r1 - case id_ecPublicKey - case secp256k1 - case Ed25519 - case rsaEncryption - /// Encryption Tags and Ciphers - case aes_128_cbc // The cipher used to encrypt an encrypted key // des_ede3_cbc - case PBKDF2 //An Encrypted PEM Key that uses PBKDF2 to derive a the AES key - case PBES2 //An Encrypted PEM Key - case unknown(Data) - - init(data:Data) { - /// Often times Object Identifiers in private keys begin with an additional 6,5 or 6,8. - /// If the objID has this prefix, we drop the first two bytes before attempting to classify... - let d = data.first == 6 ? data.dropFirst(2) : data - switch d.bytes { - case [42,134,72,206,61,2,1]: - self = .id_ecPublicKey - - case [42,134,72,206,61,3,1,7]: - self = .prime256v1 - - case [43,129,4,0,34]: - self = .secp384r1 - - case [43,129,4,0,35]: - self = .secp521r1 - - case [43,129,4,0,10]: - self = .secp256k1 - - case [43,101,112]: - self = .Ed25519 - - case [42,134,72,134,247,13,1,1,1]: - self = .rsaEncryption - - case [96,134,72,1,101,3,4,1,2]: - self = .aes_128_cbc - - case [42,134,72,134,247,13,1,5,12]: - self = .PBKDF2 - - case [42,134,72,134,247,13,1,5,13]: - self = .PBES2 - - default: - print("Found an unknown Obj ID: [\(data.map { "\($0)" }.joined(separator: ","))]") - self = .unknown(data) - } - } - - var keyType:KeyType? { - switch self { - case .secp256k1: - return .secp256K1 - case .Ed25519: - return .ed25519 - case .rsaEncryption: - return .rsa - default: //Generic EC Curves aren't supported yet... - return nil - } - } - - var description:String { - switch self { - case .prime256v1: return "prime256v1" - case .secp384r1: return "secp384r1" - case .secp521r1: return "secp521r1" - case .id_ecPublicKey: return "id_ecPublicKey" - case .secp256k1: return "secp256k1" - case .Ed25519: return "Ed25519" - case .rsaEncryption: return "rsaEncryption" - /// Encryption Tags and Ciphers.... - case .PBES2: return "PBES2" - case .PBKDF2: return "PBKDF2" - case .aes_128_cbc: return "aes_128_cbc" - case .unknown(let data): - return "Unknown Obj ID: [\(data.map { "\($0)" }.joined(separator: ","))]" - } - } - } - - /// An ASN1 node - enum Node { - case sequence(nodes: [Node]) - case integer(data: Data) - case objectIdentifier(data: ObjectIdentifier) - 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: 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) - } - - // EC Curves Cont 0 identifier (obj id) - if firstByte == 0xa0 { - let length = try scanner.consumeLength() - let data = try scanner.consume(length: length) - //print("Found an EC Curve Obj ID: [\(data.map { "\($0)" }.joined(separator: ","))]") - return .objectIdentifier(data: ObjectIdentifier(data: data)) - } - - // EC Curves Cont 1 identifier (bit string) - if firstByte == 0xa1 { - 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) - //print("Found an EC Curve Bit String: [\(data.map { "\($0)" }.joined(separator: ","))]") - return .bitString(data: data) - } - - print("Unknown byte: \([firstByte].asString(base: .base16))") - - 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] = [] - do { - while !scanner.isComplete { - let node = try parseNode(scanner: scanner) - nodes.append(node) - } - } catch { - return nodes - } - return nodes - } -} - -extension LibP2PCrypto.Keys { - - // 256 objId -> 2a8648ce3d0301 - // 384 objId -> 2a8648ce3d0201 - // 521 objId -> 2a8648ce3d0201 - public struct ASN1Parts { - let isPrivateKey:Bool - let keyBits:Data - let objectIdentifier:Data - } - - public static func parseASN1(pemData:Data) throws -> ASN1Parts { - let asn = try Asn1Parser.parse(data: pemData) - - var bitString:Data? = nil - var objId:Data? = nil - var isPrivate:Bool = false - if case .sequence(let nodes) = asn { - nodes.forEach { - switch $0 { - case .objectIdentifier(let data): - if data.first == 0x2a { - //print("Got our obj id: \(data.asString(base: .base64))") - objId = data - } - case .bitString(let data): - //print("Got our bit string: \(data.asString(base: .base64))") - bitString = data - case .sequence(let nodes): - nodes.forEach { n in - switch n { - case .objectIdentifier(let data): - if data.first == 0x2a { - //print("Got our obj id: \(data.asString(base: .base64))") - objId = data - } - case .bitString(let data): - //print("Got our bit string: \(data.asString(base: .base64))") - bitString = data - case .octetString(let data): - //Private Keys trigger - bitString = data - isPrivate = true - default: - return - } - } - case .octetString(let data): - //Private Keys trigger - bitString = data - isPrivate = true - default: - return - } - } - } - - guard let id = objId, let bits = bitString else { - throw NSError(domain: "Unsupported asn1 format", code: 0, userInfo: nil) - } - - return ASN1Parts(isPrivateKey: isPrivate, keyBits: bits, objectIdentifier: id) - - } - - public static func parseASN1ECPrivate(pemData:Data) throws -> Data { - let asn = try Asn1ParserECPrivate.parse(data: pemData) - - var octetString:Data? = nil - if case .sequence(let nodes) = asn { - nodes.forEach { - switch $0 { - case .sequence(let nodes): - nodes.forEach { n in - switch n { - case .octetString(let data): - octetString = data - default: - return - } - } - case .octetString(let data): - octetString = data - default: - return - } - } - } else if case .octetString(let data) = asn { - octetString = data - } - - guard let bits = octetString else { - throw NSError(domain: "Unsupported asn1 format", code: 0, userInfo: nil) - } - - return bits - } - - /// 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 - public static func stripX509HeaderFromDER(keyData: Data) throws -> Data { - - let node: Asn1Parser.Node - do { - node = try Asn1Parser.parse(data: keyData) - } catch { - throw NSError(domain: "asn1ParsingFailed", code: 0, userInfo: nil) - } - - // Ensure the raw data is an ASN1 sequence - guard case .sequence(let nodes) = node else { - throw NSError(domain: "invalidAsn1RootNode", code: 0, userInfo: nil) - } - - // 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 NSError(domain: "invalidAsn1Structure", code: 0, userInfo: nil) - } -} - -enum ASN1Encoder { - private static func asn1LengthPrefix(_ bytes:[UInt8]) -> [UInt8] { - if bytes.count >= 0x80 { - var lengthAsBytes = withUnsafeBytes(of: bytes.count.bigEndian, Array.init) - while lengthAsBytes.first == 0 { lengthAsBytes.removeFirst() } - return [(0x80 + UInt8(lengthAsBytes.count))] + lengthAsBytes - } else { - return [UInt8(bytes.count)] - } - } - - private static func asn1LengthPrefixed(_ bytes:[UInt8]) -> [UInt8] { - asn1LengthPrefix(bytes) + bytes - } - - public static func encode(_ node:Asn1Parser.Node) -> [UInt8] { - switch node { - case .integer(let integer): - return [0x02] + asn1LengthPrefixed(integer.bytes) - case .bitString(let bits): - return [0x03] + asn1LengthPrefixed([0x00] + bits.bytes) - case .octetString(let octet): - return [0x04] + asn1LengthPrefixed(octet.bytes) - case .null: - return [0x05, 0x00] - case .objectIdentifier(let oid): - return [0x06] + asn1LengthPrefixed(oid.bytes) - case .sequence(let nodes): - return [0x30] + asn1LengthPrefixed( nodes.reduce(into: Array(), { partialResult, node in - partialResult += encode(node) - }) ) - } - } -} - -fileprivate func printNode(_ node:Asn1Parser.Node, level:Int) -> String { - var str:[String] = [] - let prefix = String(repeating: "\t", count: level) - switch node { - case .integer(let int): - str.append("\(prefix)Integer: \(int.asString(base: .base16))") - case .bitString(let bs): - str.append("\(prefix)BitString: \(bs.asString(base: .base16))") - case .null: - str.append("\(prefix)NULL") - case .objectIdentifier(let oid): - str.append("\(prefix)ObjectID: \(oid.asString(base: .base16))") - case .octetString(let os): - str.append("\(prefix)OctetString: \(os.asString(base: .base16))") - case .sequence(let nodes): - nodes.forEach { str.append(printNode($0, level: level + 1)) } - } - return str.joined(separator: "\n") -} diff --git a/Sources/LibP2PCrypto/Utils/PEM+DER/DER.swift b/Sources/LibP2PCrypto/Utils/PEM+DER/DER.swift deleted file mode 100644 index 7429653..0000000 --- a/Sources/LibP2PCrypto/Utils/PEM+DER/DER.swift +++ /dev/null @@ -1,126 +0,0 @@ -// -// File.swift -// -// -// Created by Brandon Toms on 5/22/22. -// - -import Foundation -import Multibase - -extension LibP2PCrypto.Keys { - /// Expects a PEM Public Key with the x509 header information included (object identifier) - /// - /// - Note: Handles RSA and EC Public Keys - public static func importPublicDER(_ der:String) throws -> KeyPair { - let chunks = der.split(separator: "\n") - guard chunks.count > 3, - let f = chunks.first, f.hasPrefix("-----BEGIN RSA PUBLIC"), - let l = chunks.last, l.hasSuffix("-----") else { - throw NSError(domain: "Invalid DER Format", code: 0, userInfo: nil) - } - - let raw = try BaseEncoding.decode(chunks[1.. KeyPair { - let chunks = der.split(separator: "\n") - guard chunks.count > 3, - let f = chunks.first, f.hasPrefix("-----BEGIN RSA PRIVATE"), - let l = chunks.last, l.hasSuffix("-----") else { - throw NSError(domain: "Invalid DER Format", code: 0, userInfo: nil) - } - - var raw = try BaseEncoding.decode(chunks[1.. PrivKey { -// -// let chunks = der.split(separator: "\n") -// guard chunks.count > 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } -// -// let raw = try BaseEncoding.decode(chunks[1..? -// //let privKey = SecKeyCreateWithData(d as CFData, attributes as CFDictionary, &error) -// let privKey = SecKeyCreateFromData([:] as CFDictionary, d as CFData, &error) -// -// guard let key = privKey else { -// -// throw NSError(domain: "Failed to gen priv key... \(error.debugDescription)", code: 0, userInfo: nil) -// } -// -// if let pubkey = try? key.extractPubKey() { -// print("Got the pub key...") -// print((try? pubkey.asString(base: .base16)) ?? "nil") -// } -// -// print(key.attributes) -// -// print((try? key.rawRepresentation()) ?? "Failed to get raw rep...") -// -// return key -// -// //return try LibP2PCrypto.Keys.secKeyFrom(data: d, isPrivateKey: true, keyType: .EC(curve: .P256)) -// } - - /// Appends PEM Header and Footer - /// Base64 encodes DER PubKey - /// MacOS -> Use - /// iOS roll our own - /// https://github.com/ibm-cloud-security/Swift-JWK-to-PEM - /// https://github.com/Kitura/OpenSSL -// private func toDER(keyPair:LibP2PCrypto.Keys.KeyPair) throws -> String { -// -// // 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 keyData = try keyPair.publicKey.rawRepresentation() -// let chunks = keyData.base64EncodedString().split(intoChunksOfLength: 64) -// -// let pem = [ -// "-----BEGIN \(keyPair.keyType.name)-----", -// chunks.joined(separator: "\n"), -// "-----END \(keyPair.keyType.name)-----" -// ] -// -// return pem.joined(separator: "\n") -// } - - -} diff --git a/Sources/LibP2PCrypto/Utils/PEM+DER/PEM.swift b/Sources/LibP2PCrypto/Utils/PEM+DER/PEM.swift deleted file mode 100644 index e171376..0000000 --- a/Sources/LibP2PCrypto/Utils/PEM+DER/PEM.swift +++ /dev/null @@ -1,524 +0,0 @@ -// -// PEM.swift -// -// -// Created by Brandon Toms on 5/22/22. -// - -import Foundation -import Multibase -import Crypto - -extension LibP2PCrypto.Keys { - public struct ParsedPem { - let isPrivate:Bool - let type:KeyPairType - let rawKey:Data - } - - /// Parse the pem file into ASN1 bits... - /// Scan the bits for Object Identifiers and classify the key type - /// Based on the key type... scan the bits for the key data - /// Return a ParsedPem struct that we can use to instantiate any of our supported KeyPairTypes... - public static func parsePem(_ pem:String) throws -> KeyPair { - let chunks = pem.split(separator: "\n") - guard chunks.count >= 3, - let f = chunks.first, f.hasPrefix("-----BEGIN"), - let l = chunks.last, l.hasSuffix("-----") else { - throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) - } - - /// If its a DER re route it... - if f.contains("-----BEGIN RSA PUBLIC") { return try LibP2PCrypto.Keys.importPublicDER(pem) } - else if f.contains("-----BEGIN RSA PRIVATE") { return try LibP2PCrypto.Keys.importPrivateDER(pem) } - - let isPrivate:Bool = f.contains("PRIVATE") - - let rawPem = try BaseEncoding.decode(chunks[1.. KeyPair { - var type:KeyPairType? = nil - let asn = try Asn1ParserECPrivate.parse(data: rawPem) - - print("ASN1 Nodes") - print(asn) - print("----------") - - guard case .sequence(let nodes) = asn else { throw NSError(domain: "Failed to parse PEM", code: 0, userInfo: nil) } - let ids = objIdsInSequence(nodes) - - if ids.contains(where: { (id) -> Bool in - if case .rsaEncryption = id { return true } else { return false } - }) { - type = .RSA(bits: .B1024) //Bit length doesn't matter here, we're just broadly classifying it... - } else if ids.contains(where: { (id) -> Bool in - if case .secp256k1 = id { return true } else { return false } - }) { - type = .Secp256k1 - } else if ids.contains(where: { (id) -> Bool in - if case .Ed25519 = id { return true } else { return false } - }) { - type = .Ed25519 - } else if ids.contains(where: { (id) -> Bool in - switch id { - case .prime256v1, .secp384r1, .secp521r1: return true - default: return false - } - }) { - throw NSError(domain: "No EC Key Support Yet", code: 0, userInfo: nil) - //type = .EC(curve: .P256) //Curve bits dont matter here, we're just broadly classifying it... - } - - guard let keyType = type else { throw NSError(domain: "Failed to classify key", code: 0, userInfo: nil) } - - guard case .sequence(let top) = asn else { - throw NSError(domain: "Failed to parse Asn1", code: 0, userInfo: nil) - } - - var rawKeyData:Data? = nil - - if isPrivate { - // First Octet - guard let octet = octetsInSequence(top).first else { - throw NSError(domain: "Failed to extract \(keyType.name) \(isPrivate ? "Private" : "Public") key", code: 0, userInfo: nil) - } - rawKeyData = octet - } else { - // First Bit String... - guard let bitString = bitStringsInSequence(top).first else { - throw NSError(domain: "Failed to extract \(keyType.name) \(isPrivate ? "Private" : "Public") key", code: 0, userInfo: nil) - } - rawKeyData = bitString - } - - // ED25519 Private Keys are wrapped in an additional octetString node, lets remove it... - if isPrivate, case .Ed25519 = keyType, rawKeyData?.count == 34 { - rawKeyData?.removeFirst(2) - } - - guard let keyData = rawKeyData else { - throw NSError(domain: "Failed to extract key data from asn1 nodes", code: 0, userInfo: nil) - } - - //return ParsedPem(isPrivate: isPrivate, type: keyType, rawKey: keyData) - - // At this point we know if its a public or private key, the type of key, and the raw bits of the key. - // We can instantiate the key, ensure it's valid, then create a return a PublicKey or PrivateKey - switch keyType { - case .RSA: - if isPrivate { - return try KeyPair(privateKey: RSAPrivateKey(rawRepresentation: keyData)) - } else { - return try KeyPair(publicKey: RSAPublicKey(rawRepresentation: keyData)) - } - case .Ed25519: - if isPrivate { - return try KeyPair(privateKey: Curve25519.Signing.PrivateKey(rawRepresentation: keyData)) - } else { - return try KeyPair(publicKey: Curve25519.Signing.PublicKey(rawRepresentation: keyData)) - } - case .Secp256k1: - if isPrivate { - return try KeyPair(privateKey: Secp256k1PrivateKey(keyData.bytes)) - } else { - return try KeyPair(publicKey: Secp256k1PublicKey(keyData.bytes)) - } - //default: - /// - TODO: Internal Support For EC Keys (without support for marshaling) - // throw NSError(domain: "Unsupported Key Type \(keyType.description)", code: 0, userInfo: nil) - } - } - - /// Importes an Encrypted PEM Key File - /// - /// An ASN1 Node Tree of an Encrypted RSA PEM Key (PBKDF2 and AES_CBC_128) - /// ``` - /// sequence(nodes: [ - /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ - /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //[42,134,72,134,247,13,1,5,13] - /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ - /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ - /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //PBKDF2 //[42,134,72,134,247,13,1,5,12] - /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ - /// libp2p_crypto.Asn1Parser.Node.octetString(data: 8 bytes), //SALT - /// libp2p_crypto.Asn1Parser.Node.integer(data: 2 bytes) //ITTERATIONS - /// ]) - /// ]), - /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ - /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //des-ede3-cbc [96,134,72,1,101,3,4,1,2] - /// libp2p_crypto.Asn1Parser.Node.octetString(data: 16 bytes) //IV - /// ]) - /// ]) - /// ]), - /// libp2p_crypto.Asn1Parser.Node.octetString(data: 640 bytes) - /// ]) - /// ``` - static func parseEncryptedPem(_ pem:String, password:String) throws -> KeyPair { - let chunks = pem.split(separator: "\n") - guard chunks.count >= 3, - let f = chunks.first, f.hasPrefix("-----BEGIN ENCRYPTED"), - let l = chunks.last, l.hasSuffix("-----") else { - throw NSError(domain: "Invalid Encrypted PEM Format", code: 0, userInfo: nil) - } - - let isPrivate:Bool = f.contains("PRIVATE") - - let rawPem = try BaseEncoding.decode(chunks[1.. 100 { - ciphertextData = $0 - } else { - saltData = $0 - } - } - - /// There should be only one integer, the itteration count... - itterationsData = integersInSequence(nodes).first - - guard let salt = saltData, let iv = ivData, let itterations = itterationsData, let ciphertext = ciphertextData else { - throw NSError(domain: "Failed to parse our pcks#8 key", code: 0, userInfo: nil) - } - - // Attempt to derive the aes encryption key from the password and salt - // PBKDF2-SHA1 - guard let key = PBKDF2.SHA1(password: password, salt: salt, keyByteCount: iv.count, rounds: itterations) else { - throw NSError(domain: "Failed to derive key from password and salt", code: 0, userInfo: nil) - } - - //print("Key 1 -> \(key.asString(base: .base16))") - - //Create our CBC AES Cipher - let aes = try LibP2PCrypto.AES.createKey(key: key, iv: iv) - //let aes = try AES(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: .noPadding) - - // GCM Doesn't work on OPENSSL Encrypted PEM Files but I saw mention of it in libp2p-crypto-js so perhaps we'll need it later... - //let aes = try AES(key: key.bytes, blockMode: GCM(iv: iv.bytes, mode: .detached), padding: .noPadding) - - let decryptedKey = try aes.decrypt(ciphertext.bytes) - - // At this point we have regular unencrypted PEM data rep of a key, lets parse it... - return try self.parsePem(decryptedKey, isPrivate: isPrivate) - } - - /// Traverses a Node tree and returns all instances of integers - private static func integersInSequence(_ nodes:[Asn1ParserECPrivate.Node]) -> [Int] { - var integers:[Int?] = [] - - nodes.forEach { - if case .integer(let data) = $0 { integers.append(Int(data.asString(base: .base16), radix: 16)) } - else if case .sequence(let nodes) = $0 { - return integers.append(contentsOf: integersInSequence(nodes) ) - } - } - - return integers.compactMap { $0 } - } - - /// Traverses a Node tree and returns all instances of bitStrings - private static func bitStringsInSequence(_ nodes:[Asn1ParserECPrivate.Node]) -> [Data] { - var bitString:[Data] = [] - - nodes.forEach { - if case .bitString(let data) = $0 { bitString.append(data) } - else if case .sequence(let nodes) = $0 { - return bitString.append(contentsOf: bitStringsInSequence(nodes) ) - } - } - - return bitString - } - - /// Traverses a Node tree and returns all instances of bitStrings - private static func octetsInSequence(_ nodes:[Asn1ParserECPrivate.Node]) -> [Data] { - var octets:[Data] = [] - - nodes.forEach { - if case .octetString(let data) = $0 { octets.append(data) } - else if case .sequence(let nodes) = $0 { - return octets.append(contentsOf: octetsInSequence(nodes) ) - } - } - - return octets - } - - /// Traverses a Node tree and returns all instances of objectIds - private static func objIdsInSequence(_ nodes:[Asn1ParserECPrivate.Node]) -> [Asn1ParserECPrivate.ObjectIdentifier] { - var objs:[Asn1ParserECPrivate.ObjectIdentifier] = [] - - nodes.forEach { - if case .objectIdentifier(let id) = $0 { objs.append(id) } - else if case .sequence(let nodes) = $0 { - return objs.append(contentsOf: objIdsInSequence(nodes) ) - } - } - - return objs - } - - /// Expects a PEM Public Key with the x509 header information included (object identifier) - /// - /// - Note: Handles RSA Public Keys - public static func importPublicPem(_ pem:String) throws -> CommonPublicKey { - let chunks = pem.split(separator: "\n") - guard chunks.count > 3, - let f = chunks.first, f.hasPrefix("-----BEGIN"), - let l = chunks.last, l.hasSuffix("-----") else { - throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) - } - - let raw = try BaseEncoding.decode(chunks[1.. Data { -// let chunks = pem.split(separator: "\n") -// guard chunks.count > 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } -// -// //print("Attempting to decode: \(chunks[1.. CommonPrivateKey { - let chunks = pem.split(separator: "\n") - guard chunks.count > 3, - let f = chunks.first, f.hasPrefix("-----BEGIN PRIVATE"), - let l = chunks.last, l.hasSuffix("-----") else { - throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) - } - - //print("Attempting to decode: \(chunks[1.. PrivKey { -// let chunks = pem.split(separator: "\n") -// guard chunks.count > 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN PRIVATE"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } -// -// //print("Attempting to decode: \(chunks[1.. PubKey { -// var pubKey:Data? = nil -// switch keyType { -// case .ECDSA(curve: .P256): -// pubKey = try P256.Signing.PublicKey(pemRepresentation: pem).rawRepresentation -// case .ECDSA(curve: .P384): -// pubKey = try P384.Signing.PublicKey(pemRepresentation: pem).rawRepresentation -// case .ECDSA(curve: .P521): -// pubKey = try P521.Signing.PublicKey(pemRepresentation: pem).rawRepresentation -// default: -// print("Unsupported KeyType") -// } -// -// guard let pubKeyData = pubKey else { -// throw NSError(domain: "Unable to parse PEM into Public Key", code: 0, userInfo: nil) -// } -// -// let attributes: [String:Any] = [ -// kSecAttrKeyType as String: keyType.secKey, -// kSecAttrKeyClass as String: kSecAttrKeyClassPublic, -// kSecAttrKeySizeInBits as String: keyType.bits, -// kSecAttrIsPermanent as String: false -// ] -// -// return try LibP2PCrypto.Keys.secKeyFrom(data: pubKeyData, attributes: attributes) -// } - -// public static func initPrivKeyFromPem(_ pem:String, keyType:LibP2PCrypto.Keys.KeyPairType) throws -> PubKey { -// var pubKey:Data? = nil -// switch keyType { -// case .ECDSA(curve: .P256): -// pubKey = try P256.Signing.PrivateKey(pemRepresentation: pem).rawRepresentation -// case .ECDSA(curve: .P384): -// pubKey = try P384.Signing.PrivateKey(pemRepresentation: pem).rawRepresentation -// case .ECDSA(curve: .P521): -// pubKey = try P521.Signing.PrivateKey(pemRepresentation: pem).rawRepresentation -// default: -// print("Unsupported KeyType") -// } -// -// guard let pubKeyData = pubKey else { -// throw NSError(domain: "Unable to parse PEM into Private Key", code: 0, userInfo: nil) -// } -// -// let attributes: [String:Any] = [ -// kSecAttrKeyType as String: keyType.secKey, -// kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, -// kSecAttrKeySizeInBits as String: keyType.bits, -// kSecAttrIsPermanent as String: false -// ] -// -// return try LibP2PCrypto.Keys.secKeyFrom(data: pubKeyData, attributes: attributes) -// } - - -// public static func importPem(_ str:String) throws -> KeyPair { -// -// let pemData = str.data(using: .utf8) -// -// } - -// public static func fromPEM(_ str:String, keyType:LibP2PCrypto.Keys.KeyPairType) throws -> SecKey { -// -// guard str.hasPrefix("-----BEGIN"), str.hasSuffix("-----") else { throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) } -// let chunks = str.split(separator: "\n") -// guard chunks.count > 3 else { throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) } -// //print(chunks) -// print("Attempting to decode: \(chunks[1..? -//// let key = SecItemImport(raw.data as CFData, nil, nil, nil, .pemArmour, nil, nil, out) -//// print(key) -//// print(out) -// let attributesRSAPriv: [String:Any] = [ -// kSecAttrKeyType as String: kSecAttrKeyTypeRSA, -// kSecAttrKeyClass as String: kSecAttrKeyClassPublic, -// kSecAttrKeySizeInBits as String: keyType.bits, -// kSecAttrIsPermanent as String: false -// ] -// -// var error:Unmanaged? = nil -// guard let secKey = SecKeyCreateWithData(key as CFData, attributesRSAPriv as CFDictionary, &error) else { -// //guard let secKey = SecKeyCreateFromData(keyType.params! as CFDictionary, key as CFData, &error) else { -// throw NSError(domain: "Error constructing SecKey from raw key data: \(error.debugDescription)", code: 0, userInfo: nil) -// } -// -// return secKey -// } -} From 7e71358b9e1669c1d7f3ced70ebded729a827429 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 6 Jun 2022 19:10:42 -0700 Subject: [PATCH 11/52] Added a list of objectIdentifiers in the pemToData method to help with further classifying the Key Type when parsing / decoding a PEM file. --- Sources/LibP2PCrypto/PEM/PEM.swift | 33 ++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/Sources/LibP2PCrypto/PEM/PEM.swift b/Sources/LibP2PCrypto/PEM/PEM.swift index 6b21184..345eb11 100644 --- a/Sources/LibP2PCrypto/PEM/PEM.swift +++ b/Sources/LibP2PCrypto/PEM/PEM.swift @@ -74,6 +74,7 @@ struct PEM { case [0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x45, 0x44, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59]: self = .encryptedPrivateKey + //"BEGIN EC PRIVATE KEY" case [0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x45, 0x43, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59]: self = .ecPrivateKey @@ -123,7 +124,7 @@ struct PEM { /// Converts UTF8 Encoding of PEM file into a PEMType and the base64 decoded key data /// - Parameter data: The `UTF8` encoding of the PEM file /// - Returns: A tuple containing the PEMType, and the actual base64 decoded PEM data (with the headers and footers removed). - internal static func pemToData(_ data:Array) throws -> (type: PEMType, bytes: Array) { + internal static func pemToData(_ data:Array) throws -> (type: PEMType, bytes: Array, objectIdentifiers:[Array]) { let fiveDashes = ArraySlice(repeating: 0x2D, count: 5) // "-----".bytes.toHexString() let chunks = data.split(separator: 0x0a) // 0x0a == "\n" `new line` char guard chunks.count > 2 else { throw PEM.Error.invalidPEMFormat("expected at least 3 chunks, a header, body and footer, but got \(chunks.count)") } @@ -152,10 +153,35 @@ struct PEM { guard let base64 = String(data: Data(chunks[1.. [Data] { + if case .objectIdentifier(let id) = node { return [id] } + else if case .sequence(let nodes) = node { + return objIdsInSequence(nodes) + } + return [] + } + + /// Traverses a Node tree and returns all instances of objectIds + internal static func objIdsInSequence(_ nodes:[ASN1.Node]) -> [Data] { + var objs:[Data] = [] + + nodes.forEach { + if case .objectIdentifier(let id) = $0 { objs.append(id) } + else if case .sequence(let nodes) = $0 { + return objs.append(contentsOf: objIdsInSequence(nodes) ) + } + } + + return objs + } + /// Decodes an ASN1 formatted Public Key into it's raw DER representation /// - Parameters: /// - pem: The ASN1 encoded Public Key representation @@ -423,6 +449,7 @@ extension PEM { internal enum CipherAlgorithm { case aes_128_cbc(iv:[UInt8]) case aes_256_cbc(iv:[UInt8]) + //case des3(iv: [UInt8]) init(objID:[UInt8], iv:[UInt8]) throws { switch objID { @@ -430,6 +457,8 @@ extension PEM { self = .aes_128_cbc(iv: iv) case [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2a]: // aes-256-cbc self = .aes_256_cbc(iv: iv) + //case [42, 134, 72, 134, 247, 13, 3, 7]: + // self = .des3(iv: iv) default: throw Error.unsupportedCipherAlgorithm(objID) } From 7c592cbcab310740f7fdd78a6021b8c1461f4b93 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 6 Jun 2022 19:11:33 -0700 Subject: [PATCH 12/52] Added a PEM initializer that accepts an Array --- Sources/LibP2PCrypto/PEM/DER.swift | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Sources/LibP2PCrypto/PEM/DER.swift b/Sources/LibP2PCrypto/PEM/DER.swift index 93873b1..7d10082 100644 --- a/Sources/LibP2PCrypto/PEM/DER.swift +++ b/Sources/LibP2PCrypto/PEM/DER.swift @@ -30,16 +30,25 @@ public extension DERDecodable { /// - password: A password to use to decrypt an encrypted PEM file /// - asType: The underlying DERDecodable Key Type (ex: RSA.self) init(pem: String, password: String? = nil, asType:Key.Type = Key.self) throws { - try self.init(pem: Data(pem.utf8), password: password, asType: Key.self) + try self.init(pem: pem.bytes, password: password, asType: Key.self) } - + /// Instantiates a DERDecodable Key from ut8 decoded PEM data /// - Parameters: /// - pem: The PEM file to import /// - password: A password to use to decrypt an encrypted PEM file /// - asType: The underlying DERDecodable Key Type (ex: RSA.self) init(pem: Data, password: String? = nil, asType:Key.Type = Key.self) throws { - let (type, bytes) = try PEM.pemToData(pem.bytes) + try self.init(pem: pem.bytes, password: password, asType: Key.self) + } + + /// Instantiates a DERDecodable Key from ut8 decoded PEM bytes + /// - Parameters: + /// - pem: The PEM file to import + /// - password: A password to use to decrypt an encrypted PEM file + /// - asType: The underlying DERDecodable Key Type (ex: RSA.self) + init(pem: Array, password: String? = nil, asType:Key.Type = Key.self) throws { + let (type, bytes, _) = try PEM.pemToData(pem) if password != nil { guard type == .encryptedPrivateKey else { throw PEM.Error.invalidParameters } From e15a4f37f7a281a2bca8b2fe721c865e6d9b1371 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 6 Jun 2022 19:17:09 -0700 Subject: [PATCH 13/52] Added a PEM initializer for the KeyPair struct (this initializer attempts to classify / determine the key type for you by analyzing objectIdentifiers) --- Sources/LibP2PCrypto/Keys/KeyPair.swift | 99 +++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/Sources/LibP2PCrypto/Keys/KeyPair.swift b/Sources/LibP2PCrypto/Keys/KeyPair.swift index 1a15bdc..ae5c200 100644 --- a/Sources/LibP2PCrypto/Keys/KeyPair.swift +++ b/Sources/LibP2PCrypto/Keys/KeyPair.swift @@ -233,3 +233,102 @@ extension LibP2PCrypto.Keys { } } } + + +extension LibP2PCrypto.Keys.KeyPair { + init(pem:String, password:String? = nil) throws { + try self.init(pem: pem.bytes, password: password) + } + + init(pem:Data, password:String? = nil) throws { + try self.init(pem: pem.bytes, password: password) + } + + init(pem pemBytes:Array, password:String? = nil) throws { + + let (type, bytes, ids) = try PEM.pemToData(pemBytes) + + if password != nil { + guard type == .encryptedPrivateKey else { throw PEM.Error.invalidParameters } + } + + switch type { + case .publicRSAKeyDER: + // Ensure the objectIdentifier is rsaEncryption + try self.init(publicKey: RSAPublicKey(publicDER: bytes)) + + case .privateRSAKeyDER: + // Ensure the objectIdentifier is rsaEncryption + try self.init(privateKey: RSAPrivateKey(privateDER: bytes)) + + case .publicKey: + // Attempt to further classify the pem into it's exact key type + if ids.contains(RSAPublicKey.primaryObjectIdentifier) { + try self.init(publicKey: RSAPublicKey(pem: pemBytes, asType: RSAPublicKey.self)) + } else if ids.contains(Curve25519.Signing.PublicKey.primaryObjectIdentifier) { + try self.init(publicKey: Curve25519.Signing.PublicKey(pem: pemBytes, asType: Curve25519.Signing.PublicKey.self)) + } else if ids.contains(Secp256k1PublicKey.primaryObjectIdentifier) { + try self.init(publicKey: Secp256k1PublicKey(pem: pemBytes, asType: Secp256k1PublicKey.self)) + } else { + throw PEM.Error.unsupportedPEMType + } + + case .privateKey, .ecPrivateKey: + // Attempt to further classify the pem into it's exact key type + if ids.contains(RSAPrivateKey.primaryObjectIdentifier) { + try self.init(privateKey: RSAPrivateKey(pem: pemBytes, asType: RSAPrivateKey.self)) + } else if ids.contains(Curve25519.Signing.PrivateKey.primaryObjectIdentifier) { + try self.init(privateKey: Curve25519.Signing.PrivateKey(pem: pemBytes, asType: Curve25519.Signing.PrivateKey.self)) + } else if ids.contains(Secp256k1PrivateKey.primaryObjectIdentifier) { + try self.init(privateKey: Secp256k1PrivateKey(pem: pemBytes, asType: Secp256k1PrivateKey.self)) + } else { + throw PEM.Error.unsupportedPEMType + } + + case .encryptedPrivateKey: + // Decrypt the encrypted PEM and attempt to instantiate it again... + + // Ensure we were provided a password + guard let password = password else { throw PEM.Error.invalidParameters } + + // Parse out Encryption Strategy and CipherText + let decryptionStategy = try PEM.decodeEncryptedPEM(Data(bytes)) // RSA.decodeEncryptedPEM(Data(bytes)) + + // Derive Encryption Key from Password + let key = try decryptionStategy.pbkdfAlgorithm.deriveKey(password: password, ofLength: decryptionStategy.cipherAlgorithm.desiredKeyLength) + + // Decrypt CipherText + let decryptedPEM = try decryptionStategy.cipherAlgorithm.decrypt(bytes: decryptionStategy.ciphertext, withKey: key) + + // Extract out the objectIdentifiers from the decrypted pem + let ids = try PEM.objIdsInSequence(ASN1.Decoder.decode(data: Data(decryptedPEM))).map { $0.bytes } + + // Attempt to classify the Key Type + if ids.contains(RSAPrivateKey.primaryObjectIdentifier) { + let der = try PEM.decodePrivateKeyPEM( + Data(decryptedPEM), + expectedPrimaryObjectIdentifier: RSAPrivateKey.primaryObjectIdentifier, + expectedSecondaryObjectIdentifier: RSAPrivateKey.secondaryObjectIdentifier + ) + try self.init(privateKey: RSAPrivateKey(privateDER: der)) + } else if ids.contains(Curve25519.Signing.PrivateKey.primaryObjectIdentifier) { + let der = try PEM.decodePrivateKeyPEM( + Data(decryptedPEM), + expectedPrimaryObjectIdentifier: Curve25519.Signing.PrivateKey.primaryObjectIdentifier, + expectedSecondaryObjectIdentifier: Curve25519.Signing.PrivateKey.secondaryObjectIdentifier + ) + try self.init(privateKey: Curve25519.Signing.PrivateKey(privateDER: der)) + } else if ids.contains(Secp256k1PrivateKey.primaryObjectIdentifier) { + let der = try PEM.decodePrivateKeyPEM( + Data(decryptedPEM), + expectedPrimaryObjectIdentifier: Secp256k1PrivateKey.primaryObjectIdentifier, + expectedSecondaryObjectIdentifier: Secp256k1PrivateKey.secondaryObjectIdentifier + ) + try self.init(privateKey: Secp256k1PrivateKey(privateDER: der)) + } else { + print(ids) + throw PEM.Error.unsupportedPEMType + } + } + } +} From eb9de19e89ef5dc395a5cb9ed93a4fa7d3f44d46 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 6 Jun 2022 19:18:51 -0700 Subject: [PATCH 14/52] Removed the dependency on the RSAPublicKeyImporterExporter package. --- Package.swift | 6 +-- .../Keys/Types/RSA/RSA+SecKey.swift | 52 ++++++++----------- 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/Package.swift b/Package.swift index d6ac122..a028956 100644 --- a/Package.swift +++ b/Package.swift @@ -21,7 +21,7 @@ let package = Package( // Protobuf Marshaling .package(url: "https://github.com/apple/swift-protobuf.git", .upToNextMajor(from: "1.12.0")), // RSA Import / Export Support - .package(url: "https://github.com/nextincrement/rsa-public-key-importer-exporter.git", .upToNextMajor(from: "0.1.0")), + //.package(url: "https://github.com/nextincrement/rsa-public-key-importer-exporter.git", .upToNextMajor(from: "0.1.0")), // Secp256k1 Support .package(url: "https://github.com/Boilertalk/secp256k1.swift.git", .exact("0.1.6")), // 🔑 Hashing (BCrypt, SHA2, HMAC), encryption (AES), public-key (RSA), PEM and DER file handling, and random data generation. @@ -40,8 +40,8 @@ let package = Package( .product(name: "Multibase", package: "swift-multibase"), .product(name: "Multihash", package: "swift-multihash"), .product(name: "SwiftProtobuf", package: "swift-protobuf"), - .product(name: "RSAPublicKeyExporter", package: "rsa-public-key-importer-exporter"), - .product(name: "RSAPublicKeyImporter", package: "rsa-public-key-importer-exporter"), + //.product(name: "RSAPublicKeyExporter", package: "rsa-public-key-importer-exporter"), + //.product(name: "RSAPublicKeyImporter", package: "rsa-public-key-importer-exporter"), .product(name: "secp256k1", package: "secp256k1.swift"), .product(name: "Crypto", package: "swift-crypto"), .product(name: "CryptoSwift", package: "CryptoSwift"), diff --git a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+SecKey.swift b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+SecKey.swift index 6b22a19..7be1719 100644 --- a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+SecKey.swift +++ b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+SecKey.swift @@ -9,8 +9,8 @@ import Foundation import Multibase import Security -import RSAPublicKeyImporter -import RSAPublicKeyExporter +//import RSAPublicKeyImporter +//import RSAPublicKeyExporter struct RSAPublicKey:CommonPublicKey { static var keyType: LibP2PCrypto.Keys.GenericKeyType { .rsa } @@ -39,11 +39,29 @@ struct RSAPublicKey:CommonPublicKey { } init(marshaledData data: Data) throws { - try self.init(rawRepresentation: try RSAPublicKeyImporter().fromSubjectPublicKeyInfo(data)) + let asn = try ASN1.Decoder.decode(data: data) + guard case .sequence(let nodes) = asn else { throw NSError(domain: "RSAPublicKey Invalid marshaled data", code: 0) } + guard case .sequence(let subjectInfo) = nodes[0] else { throw NSError(domain: "RSAPublicKey Invalid marshaled data", code: 0) } + guard case .objectIdentifier(let objID) = subjectInfo.first else { throw NSError(domain: "RSAPublicKey Invalid marshaled data", code: 0) } + guard objID.bytes == RSAPublicKey.primaryObjectIdentifier else { throw NSError(domain: "RSAPublicKey Invalid marshaled data", code: 0) } + guard case .bitString(let bits) = nodes[1] else { throw NSError(domain: "RSAPublicKey Invalid marshaled data", code: 0) } + try self.init(rawRepresentation: bits) + + //try self.init(rawRepresentation: try RSAPublicKeyImporter().fromSubjectPublicKeyInfo(data)) } var rawRepresentation: Data { - try! RSAPublicKeyExporter().toSubjectPublicKeyInfo(self.key.rawRepresentation()) + let asnNodes:ASN1.Node = try! .sequence(nodes: [ + .sequence(nodes: [ + .objectIdentifier(data: Data(RSAPublicKey.primaryObjectIdentifier)), + .null + ]), + .bitString(data: self.key.rawRepresentation()) + ]) + + return Data(ASN1.Encoder.encode(asnNodes)) + + //try! RSAPublicKeyExporter().toSubjectPublicKeyInfo(self.key.rawRepresentation()) //try! self.key.rawRepresentation() } @@ -216,36 +234,10 @@ internal extension SecKey { return cfdata as Data } else { throw NSError(domain: "RawKeyError: \(error.debugDescription)", code: 0, userInfo: nil) } } -} - -internal extension SecKey { - - /// Gets the ID of the key. - /// - /// The key id is the base58 encoding of the SHA-256 multihash of its public key. - /// The public key is a protobuf encoding containing a type and the DER encoding - /// of the PKCS SubjectPublicKeyInfo. -// func id(keyType: LibP2PCrypto.Keys.KeyPairType, withMultibasePrefix:Bool = true) throws -> String { -// -// guard let pubKey = SecKeyCopyPublicKey(self) else { -// throw NSError(domain: "Public Key Extraction Error", code: 0, userInfo: nil) -// } -// -// /// The key id is the base58 encoding of the SHA-256 multihash of its public key. -// /// The public key is a protobuf encoding containing a type and the DER encoding -// /// of the PKCS SubjectPublicKeyInfo. -// let marshaledPubKey = try LibP2PCrypto.Keys.marshalPublicKey(pubKey, keyType: keyType) -// let mh = try Multihash(raw: marshaledPubKey, hashedWith: .sha2_256) -// return withMultibasePrefix ? mh.asMultibase(.base58btc) : mh.asString(base: .base58btc) -// } var attributes:CFDictionary? { return SecKeyCopyAttributes(self) } - - func subjectKeyInfo() throws -> Data { - return try RSAPublicKeyExporter().toSubjectPublicKeyInfo(self.rawRepresentation()) - } } #endif From e97e4553302765b7db097b158fa10549dc98e038 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 6 Jun 2022 19:19:34 -0700 Subject: [PATCH 15/52] Updated to be compatible with the new ASN1 encoder / decoder --- .../Keys/Types/RSA/RSA+CryptoSwift.swift | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift index 1f00b68..bd5db78 100644 --- a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift +++ b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift @@ -23,7 +23,7 @@ struct RSAPublicKey:CommonPublicKey { } init(rawRepresentation raw: Data) throws { - let asn1 = try Asn1Parser.parse(data: raw) + let asn1 = try ASN1.Decoder.decode(data: raw) guard case .sequence(let params) = asn1 else { throw NSError(domain: "Invalid ASN1 Encoding -> \(asn1)", code: 0) } @@ -33,7 +33,7 @@ struct RSAPublicKey:CommonPublicKey { guard oid.bytes == RSAPublicKey.RSA_OBJECT_IDENTIFIER else { throw NSError(domain: "Invalid ASN1 Encoding -> ObjectID != Public RSA Key ID", code: 0) } guard case .bitString(let bits) = params.last else { throw NSError(domain: "Invalid ASN1 Encoding -> No BitString", code: 0) } - guard case .sequence(let params2) = try Asn1Parser.parse(data: bits) else { throw NSError(domain: "Invalid ASN1 Encoding -> No PubKey Sequence", code: 0) } + guard case .sequence(let params2) = try ASN1.Decoder.decode(data: bits) else { throw NSError(domain: "Invalid ASN1 Encoding -> No PubKey Sequence", code: 0) } guard case .integer(let n) = params2.first else { throw NSError(domain: "Invalid ASN1 Encoding -> No Modulus", code: 0) } guard case .integer(let e) = params2.last else { throw NSError(domain: "Invalid ASN1 Encoding -> No Public Exponent", code: 0) } @@ -56,21 +56,21 @@ struct RSAPublicKey:CommonPublicKey { /// We return the ASN1 Encoded DER Representation of the public key because that's what the rewRepresentation of RSA SecKey return var rawRepresentation: Data { let mod = key.n.serialize() - let pubkeyAsnNode:Asn1Parser.Node = + let pubkeyAsnNode:ASN1.Node = .sequence(nodes: [ .integer(data: Data(CryptoSwift.RSA.zeroPad(n: mod.bytes, to: mod.count + 1))), .integer(data: key.e.serialize()) ]) - let asnNodes:Asn1Parser.Node = .sequence(nodes: [ + let asnNodes:ASN1.Node = .sequence(nodes: [ .sequence(nodes: [ .objectIdentifier(data: Data(RSAPublicKey.RSA_OBJECT_IDENTIFIER)), .null ]), - .bitString(data: Data(ASN1Encoder.encode(pubkeyAsnNode))) + .bitString(data: Data(ASN1.Encoder.encode(pubkeyAsnNode))) ]) - return Data(ASN1Encoder.encode(asnNodes)) + return Data(ASN1.Encoder.encode(asnNodes)) } func encrypt(data: Data) throws -> Data { @@ -124,7 +124,7 @@ struct RSAPrivateKey:CommonPrivateKey { /// Expects the ASN1 Encoding of the DER formatted RSA Private Key init(rawRepresentation raw: Data) throws { - guard case .sequence(let params) = try Asn1Parser.parse(data: raw) else { throw NSError(domain: "Invalid ASN1 Encoding -> No PrivKey Sequence", code: 0) } + guard case .sequence(let params) = try ASN1.Decoder.decode(data: raw) else { throw NSError(domain: "Invalid ASN1 Encoding -> No PrivKey Sequence", code: 0) } // We check for 4 here because internally we can only marshal the first 4 integers at the moment... guard params.count == 4 || params.count == 9 else { throw NSError(domain: "Invalid ASN1 Encoding -> Invalid Private RSA param count. Expected 9 got \(params.count)", code: 0) } guard case .integer(let n) = params[1] else { throw NSError(domain: "Invalid ASN1 Encoding -> PrivKey No Modulus", code: 0) } @@ -141,14 +141,14 @@ struct RSAPrivateKey:CommonPrivateKey { var rawRepresentation: Data { guard let d = key.d else { /*throw NSError(domain: "Not a valid private RSA Key", code: 0)*/ return Data() } let mod = key.n.serialize() - let privkeyAsnNode:Asn1Parser.Node = + let privkeyAsnNode:ASN1.Node = .sequence(nodes: [ .integer(data: Data( Array(arrayLiteral: 0x00) )), .integer(data: Data(CryptoSwift.RSA.zeroPad(n: mod.bytes, to: mod.count + 1))), .integer(data: key.e.serialize()), .integer(data: d.serialize()) ]) - return Data(ASN1Encoder.encode(privkeyAsnNode)) + return Data(ASN1.Encoder.encode(privkeyAsnNode)) } func derivePublicKey() throws -> CommonPublicKey { @@ -272,7 +272,7 @@ extension CryptoSwift.RSA { /// 2. Encode the algorithm ID for the hash function and the hash value into an ASN.1 value of type DigestInfo /// PKCS#1_15 DER Structure (OID == sha256WithRSAEncryption) - let asn:Asn1Parser.Node = .sequence(nodes: [ + let asn:ASN1.Node = .sequence(nodes: [ .sequence(nodes: [ .objectIdentifier(data: Data(Array(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01))), .null @@ -280,7 +280,7 @@ extension CryptoSwift.RSA { .octetString(data: Data(hashedMessage)) ]) - let t = ASN1Encoder.encode(asn) + let t = ASN1.Encoder.encode(asn) /// 3. If emLen < tLen + 11, output "intended encoded message lengthtoo short" and stop if modLength < t.count + 11 { throw NSError(domain: "intended encoded message length too short", code: 0) } From 86e1b257f2a0d816593e7ed3ea9cf3980778741f Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 6 Jun 2022 19:20:24 -0700 Subject: [PATCH 16/52] Created a separate file for the new potential test fixture structure --- Tests/LibP2PCryptoTests/pem.swift | 180 ---------------------- Tests/LibP2PCryptoTests/signatures.swift | 188 +++++++++++++++++++++++ 2 files changed, 188 insertions(+), 180 deletions(-) create mode 100644 Tests/LibP2PCryptoTests/signatures.swift diff --git a/Tests/LibP2PCryptoTests/pem.swift b/Tests/LibP2PCryptoTests/pem.swift index 1d506f4..dc136fc 100644 --- a/Tests/LibP2PCryptoTests/pem.swift +++ b/Tests/LibP2PCryptoTests/pem.swift @@ -584,183 +584,3 @@ struct TestPEMKeys { """ } - - -//struct TestFixtures { -// struct Fixture { -// let publicPEM:String -// let privatePEM:String -// let rawMessage:String -// let encryptedMessage:[String:String] -// let signedMessages:[String:String] -// let publicMarshaled:String -// let privateMarshaled:String -// } -// -// static let RSA_1024 = Fixture( -// publicPEM: """ -// -//""", -// privatePEM: """ -//-----BEGIN PRIVATE KEY----- -//MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANSRvSiXv+gtFt9s -//upxbjfG0l2HvFD5V/nsNa2QSl5+Vnl9RMg0P6zUCVMC/rc2x9RfcYn+n7mOGeXfP -//B5Mqvt7mFoxmo4loBFIqkbE4HDPUrduG8lb6LNfBSvA9tyaSICW+QCyOPWHBGk0P -//y382i4X6E7ActAI++RfxgttTOhmvAgMBAAECgYAyjMnf+l5ft0FGNpQWFMunnBuX -//5YP54vdWifVs4eL+x1TXM/bkFlIH1BsVjz+kt9oiJ32g/+1364W9URVrEPI8nk5i -//Id40q3Qiozvn4ceWtSoCGmuxIbdRqL1JJn5e8Zfzs7E8KZimYu00t2qcidFDUsEC -//biCqT14UNcbpwsOpkQJBAPxMogs3OnkgCWlptZckjg+srwxnXIkzDhSO+WaKl2Dm -//DvSMnB2Ws64EDu2dP+HLiuoyqG/ZqRabdQqIsIrkLpkCQQDXr+wYGoOiL26PrAew -//z49aH/wQZq8fBM2yuwvR+ZDRraQ0otQV1aRwffqlI+IfYowJvyPX+EC/ftcff0qa -//6R+HAkAQZlrSJ9DhNrfl5j0rifDCDBOE1uMo9+yeYXzMsY2NeubV9p3fPoCHezQN -//Nf+FCdoJxykzvA5Fre05thDjtllhAkEAgdsf2M81y1KlTQi0xKXiV8+D8dfwvUsm -//EOJ+Vlfb8fGKOEqER/UNgNDIM96ryFuLll6m1ONZEDHskMERiLysRwJAawkNDlqe -//sIjqrfR2luw+TLHkMI0T6pTY9s+79F9VVV/V13v2qtTpXw1eu7Sw+oDBpJoocz/h -//+YzU+CyyzO+qUA== -//-----END PRIVATE KEY----- -//""", -// rawMessage: "Hello RSA Signatures!", -// encryptedMessage: [ -// "algid:encrypt:RSA:raw": "N2T56NKkKAFdCytLP9zT0Iu9N0KNKkflB6vsNl6G+nkY/102laZLSbNZbdkzsOYSIml30ZaQSPS76aBuAYttlnCNEckgwmaS2IpHnFcUUFa/MOf+LJRcDXvkp+NoAmF0QFUhQ+VPfdineUrzOkL+xUi4hY614su6VdfPVmtJeog=", -// "algid:encrypt:RSA:PKCS1": "uliKMjgMn54C/WmwagE0dHFrEKw9civz9YYkHS+KKdlqVeCf9qKrFoSHlpA1Mq4JFg0WmpLWaMxgBaD+1CrE4Y+k26+wa4JtffLbyabYrxJkNQ5Am99KnoZO8rLEp2VumxGcsWWseMgSqrlO9KTesD8sJGFCMiz6aSFieedjAu4=" -// ], -// signedMessages: [ -// "algid:sign:RSA:raw" : "zpIDplKEdLvsHopjwoC36mQ3SRg2mZe/0RPP3DaDMnlSDLneoGwzR/L4oR/PTxD34wW7edQV4z5MrFSbmK4a7d+fwvNRQtwYlw/L04GTQyH8G6LhFUKL+++0jdPOMuMXADT8Yfrna6QHti2kqcUE4WSXHe6yY8xZZ6SHEDK71zg=", -// "algid:sign:RSA:digest-PKCS1v15" : "s64/o2jeSm9OsTwlBuwJXOkJQPLoT300ZnMPDwfAdKsVFq8vR0uUDgkKYGnaogRu66QTWHfjSPcO2RUKV23141GM6Tng3zv3WGQm2Eg663n+9tYpsV5hCussJAcAwuGHoZwFV79alpNZkFyHEjya189zPeT1K3FbZJniL0ykTuk=", -// "algid:sign:RSA:digest-PKCS1v15:SHA1" : "zIqv0mqhlDl0pf/Z5cRuZSP8oskOJhwluNI9EJRBC8b3RXlPlj2BzZyNbN0Mys3joVlfEiw4YsKYKFWN3SwGSwsYfcfeWpDJ5vJF3s32JkXnfHLdspTeapeVYDSy4MS8mNkVbYB6pQFBNK6scfzUFY7pLPKzUJ1MCnRmwpc0MbU=", -// "algid:sign:RSA:digest-PKCS1v15:SHA224" : "TS9eVlAFagKSmHtSdjunj3hgqQY5Zu7agjeYPvChB+jPgoqw/H3QwdzA4deZgcmsE1BooCgK9/1iekEWU/tjilVVrkhB5Kq5YxAWA7+IBo5pYFbmsAvP4ka+Oq1urfAYQbzTAuFyEXbdfXQATotElZFHwWjlTvZyk/IFfEawqtg=", -// "algid:sign:RSA:digest-PKCS1v15:SHA256" : "bLshLiyA9r2aow0u3+UKTSnyght7+8MuxEFzKsQrKgi9wYNwXsZEToB7jZ6+Y/hbezdIYXHwdtkHmBslAQBEGk+njsggrtWPVSDu/yU6icjEiiEd/35tVzgFejhmhj/5b8odScLrJF+6IeDl4iv9/tQZ7znOGImg5nZSik9c6dI=", -// "algid:sign:RSA:digest-PKCS1v15:SHA384" : "N810I+DcCYE7RROmKCHFl7MZl34dHkIx6Y3TxWv5g/JfvZHGRf+TwaFDjD7cGAdV+jY4wZd6mSNZvrhLgfb8t2X5JOaIiDaXt39etAywgE7OuMMYZsD596UBQFrdEu0bQIsK3+D+GcRCNYFVUUsJmYLvo/cio59IcTSRu1f3/5Y=", -// "algid:sign:RSA:digest-PKCS1v15:SHA512" : "rvrbc/LRhgGbXq1yAybMxfejAf+GHi4bcrhNKMRtg+RT3iw+Z5KLKzcSWinD9yH1j8NrL8u7EPLNDQ6EGt8y0JYSk0KqwseBpC2/zicu2HTypzFLnrNDtAw6E1A+AVOoAPkxkKf8F/ledih4xKn884USD2jO4ncyoXK4sGj0sjA=", -// "algid:sign:RSA:message-PKCS1v15:SHA1" : "BMmnNyAMr8CMYpiZJAngT1o7wDGB1+hrHBHCs5OLcM/bpzqJ8+L9hHnWBeh4hZGcIkRCnB5KFd42WwcNLUQi1EUQHvDDH9gwpT8oPWn7Y/bkflwtKl9A3R1RiobY2rafe5PlbKW+SlN8ddZ0gevt5w7Ob+vQYRLu+e5dSSxVrtY=", -// "algid:sign:RSA:message-PKCS1v15:SHA224": "Ro+Y9+TavJt18Bin3+WVVg3YOzPsIlky7LiPXkMdsh1Zq5j3CD23EehNIG2HT3QXSG2ySZuaEj0swJvJWEvcmc1lo8f0xONkgCSk8iKtRzoJ6AJe3abqwc2gNHofzUtJq/eh2ZCO/IFvXC0B4sMIf2ztJuSNRW9O8d0m8zCsHZo=", -// "algid:sign:RSA:message-PKCS1v15:SHA256": "kaqP1oUrtRPUTA5uBAcPrIDGQPAqn8uH9pHMFYumS9FwZTYlRAeCFliMuiyW79x+x+BOC6TX+mipXgWJIO1IaucyrLBKlak934SX6q71xWA74SSYlMEzalKPFpi879fvgGyY4fRypJQv5uZ3nvlvxAhyB/pX7jaV07ct9sKIQv4=", -// "algid:sign:RSA:message-PKCS1v15:SHA384": "hxsA7RjGU97s1erJAv1WTkscZk61NHv55s0BWHoJEXgda0WulbcnOQduZJWeSyxJjRh4kGztV42xOvMpo9qcovbYOI3hQJ210gbNTBKmTp9tG79ShV6lx07eceC2XZg9kYxtgkuSpurRjd2PFbkGFGhTZmqRaSQukPjSIhnxoyQ=", -// "algid:sign:RSA:message-PKCS1v15:SHA512": "r31GD74cN5wknycZDyNZdJ4HJBBLv5zMH+dmfYW98i3szDS8txdr0M8ZrmM0jLxcSpwa5461vwMBhyCOYlqY2y3HoKNolIDSANhWPufKFMcv+ob3okNDQGXOAyPKhxn/EW7X2Mz3XQlBnOA6c18KR3UnZvoW5wn9K1tpv4ueEyI=" -// ], -// publicMarshaled: "CAASogEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANSRvSiXv+gtFt9supxbjfG0l2HvFD5V/nsNa2QSl5+Vnl9RMg0P6zUCVMC/rc2x9RfcYn+n7mOGeXfPB5Mqvt7mFoxmo4loBFIqkbE4HDPUrduG8lb6LNfBSvA9tyaSICW+QCyOPWHBGk0Py382i4X6E7ActAI++RfxgttTOhmvAgMBAAE=", -// privateMarshaled: "CAAS4AQwggJcAgEAAoGBANSRvSiXv+gtFt9supxbjfG0l2HvFD5V/nsNa2QSl5+Vnl9RMg0P6zUCVMC/rc2x9RfcYn+n7mOGeXfPB5Mqvt7mFoxmo4loBFIqkbE4HDPUrduG8lb6LNfBSvA9tyaSICW+QCyOPWHBGk0Py382i4X6E7ActAI++RfxgttTOhmvAgMBAAECgYAyjMnf+l5ft0FGNpQWFMunnBuX5YP54vdWifVs4eL+x1TXM/bkFlIH1BsVjz+kt9oiJ32g/+1364W9URVrEPI8nk5iId40q3Qiozvn4ceWtSoCGmuxIbdRqL1JJn5e8Zfzs7E8KZimYu00t2qcidFDUsECbiCqT14UNcbpwsOpkQJBAPxMogs3OnkgCWlptZckjg+srwxnXIkzDhSO+WaKl2DmDvSMnB2Ws64EDu2dP+HLiuoyqG/ZqRabdQqIsIrkLpkCQQDXr+wYGoOiL26PrAewz49aH/wQZq8fBM2yuwvR+ZDRraQ0otQV1aRwffqlI+IfYowJvyPX+EC/ftcff0qa6R+HAkAQZlrSJ9DhNrfl5j0rifDCDBOE1uMo9+yeYXzMsY2NeubV9p3fPoCHezQNNf+FCdoJxykzvA5Fre05thDjtllhAkEAgdsf2M81y1KlTQi0xKXiV8+D8dfwvUsmEOJ+Vlfb8fGKOEqER/UNgNDIM96ryFuLll6m1ONZEDHskMERiLysRwJAawkNDlqesIjqrfR2luw+TLHkMI0T6pTY9s+79F9VVV/V13v2qtTpXw1eu7Sw+oDBpJoocz/h+YzU+CyyzO+qUA==" -// ) -//} - - -//func testRSAPEMImportSignAndVerify() throws { -// let expectedSignature: Array = [ -// 0x76, 0xEB, 0x7F, 0x10, 0x95, 0x40, 0xC9, 0x19, 0xE6, 0x44, 0x6F, 0xCD, 0x88, 0x83, 0x22, 0x6E, -// 0x5C, 0xE4, 0x1E, 0x87, 0xE3, 0xAF, 0x3B, 0x59, 0xB7, 0xB2, 0x89, 0xFD, 0x88, 0x37, 0xC0, 0xCE, -// 0xEA, 0x0E, 0x87, 0x06, 0x5F, 0x6E, 0xE7, 0x8C, 0xE9, 0x3F, 0xD6, 0xC3, 0xE0, 0x0B, 0x94, 0x19, -// 0xAC, 0x58, 0x2D, 0x73, 0xD3, 0x92, 0x45, 0x2C, 0x66, 0x7F, 0xB5, 0x24, 0xC6, 0xEA, 0xC6, 0xE2, -// 0x0E, 0xBB, 0x12, 0x86, 0x5B, 0xF4, 0x1D, 0x25, 0x2F, 0x68, 0x69, 0x30, 0x80, 0x4D, 0x10, 0xDF, -// 0x25, 0x5E, 0x00, 0x1D, 0x2F, 0x5F, 0x67, 0xE5, 0x4C, 0x7D, 0x1E, 0x64, 0xB2, 0x0B, 0xE8, 0x19, -// 0xE6, 0xB8, 0x62, 0xA6, 0xD1, 0x66, 0x58, 0x47, 0xAC, 0xAB, 0xAB, 0xCD, 0x26, 0x3D, 0x16, 0x52, -// 0xBF, 0x35, 0xB0, 0x21, 0xE2, 0xE3, 0x48, 0x77, 0x1E, 0x81, 0xE8, 0xCF, 0x75, 0x67, 0x64, 0x2A -// ] -// -// let message = "Hello RSA Signatures!".data(using: .utf8)! -// -// let keyPair = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.RSA_1024_PRIVATE) -// -// let secKey = try initSecKey(rawRepresentation: keyPair.privateKey!.rawRepresentation) -// -// let privateMarshaled = try keyPair.privateKey?.marshal() -// print(privateMarshaled!.asString(base: .base64Pad)) -// -// let publicMarsheled = try keyPair.marshalPublicKey() -// print(publicMarsheled.asString(base: .base64Pad)) -// -// let pemData = try secKey.extractPubKey().rawRepresentation() -// -// let pem = "-----BEGIN PUBLIC KEY-----\n" + pemData.asString(base: .base64Pad).split(intoChunksOfLength: 64).joined(separator: "\n") + "\n-----END PUBLIC KEY-----" -// -// print(pem) -// -// try sign(message: message, using: secKey)//keyPair.sign(message: message) -// -// try encrypt(data: message, with: secKey.extractPubKey()) -// -//// printHexData16BytesWide(signature.bytes) -//// print(signature.asString(base: .base64Pad)) -//// -//// XCTAssertEqual(signature.bytes, expectedSignature) -//} -// -//private func printHexData16BytesWide(_ bytes:[UInt8]) { -// print(bytes.toHexString().split(intoChunksOfLength: 32).map { $0.split(intoChunksOfLength: 2).map { "0x\($0.uppercased())" }.joined(separator: ", ") }.joined(separator: ",\n")) -//} -// -//private func initSecKey(rawRepresentation raw: Data) throws -> SecKey { -// let attributes: [String:Any] = [ -// kSecAttrKeyType as String: kSecAttrKeyTypeRSA, -// kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, -// kSecAttrKeySizeInBits as String: 1024, -// kSecAttrIsPermanent as String: false -// ] -// -// var error:Unmanaged? = nil -// guard let secKey = SecKeyCreateWithData(raw as CFData, attributes as CFDictionary, &error) else { -// throw NSError(domain: "Error constructing SecKey from raw key data: \(error.debugDescription)", code: 0, userInfo: nil) -// } -// -// return secKey -//} -// -//private func sign(message: Data, using key: SecKey) throws { -// let algorithms:[SecKeyAlgorithm] = [ -// .rsaSignatureRaw, -// //.rsaSignatureDigestPSSSHA1, -// //.rsaSignatureDigestPSSSHA224, -// //.rsaSignatureDigestPSSSHA256, -// //.rsaSignatureDigestPSSSHA384, -// //.rsaSignatureDigestPSSSHA512, -// .rsaSignatureDigestPKCS1v15Raw, -// .rsaSignatureDigestPKCS1v15SHA1, -// .rsaSignatureDigestPKCS1v15SHA224, -// .rsaSignatureDigestPKCS1v15SHA256, -// .rsaSignatureDigestPKCS1v15SHA384, -// .rsaSignatureDigestPKCS1v15SHA512, -// //.rsaSignatureMessagePSSSHA1, -// //.rsaSignatureMessagePSSSHA224, -// //.rsaSignatureMessagePSSSHA256, -// //.rsaSignatureMessagePSSSHA384, -// //.rsaSignatureMessagePSSSHA512, -// .rsaSignatureMessagePKCS1v15SHA1, -// .rsaSignatureMessagePKCS1v15SHA224, -// .rsaSignatureMessagePKCS1v15SHA256, -// .rsaSignatureMessagePKCS1v15SHA384, -// .rsaSignatureMessagePKCS1v15SHA512, -// ] -// -// for algo in algorithms { -// var error: Unmanaged? -// -// // Sign the data -// guard let signature = SecKeyCreateSignature( -// key, -// algo, -// message as CFData, -// &error) as Data? -// else { print("\"\(algo.rawValue)\": \"nil\","); continue } -// -// // Throw the error if we encountered one -// if let error = error { print("\"\(algo.rawValue)\": \"\(error.takeRetainedValue())\","); continue } -// -// // Return the signature -// print("\"\(algo.rawValue)\": \"\(signature.asString(base: .base64Pad))\",") -// } -// -//} -// -//private func encrypt(data: Data, with key:SecKey) throws { -// let algorithms:[SecKeyAlgorithm] = [ -// .rsaEncryptionRaw, -// .rsaEncryptionPKCS1 -// ] -// -// for algo in algorithms { -// var error:Unmanaged? -// guard let encryptedData = SecKeyCreateEncryptedData(key, .rsaEncryptionPKCS1, data as CFData, &error) else { -// print("\"\(algo.rawValue)\": \"\(error?.takeRetainedValue().localizedDescription ?? "nil")\","); continue -// } -// print("\"\(algo.rawValue)\": \"\((encryptedData as Data).asString(base: .base64Pad))\",") -// } -//} diff --git a/Tests/LibP2PCryptoTests/signatures.swift b/Tests/LibP2PCryptoTests/signatures.swift new file mode 100644 index 0000000..c896b97 --- /dev/null +++ b/Tests/LibP2PCryptoTests/signatures.swift @@ -0,0 +1,188 @@ +// +// signatures.swift +// +// +// Created by Brandon Toms on 6/6/22. +// + +import Foundation + + +struct TestFixtures { + struct Fixture { + let publicPEM:String + let privatePEM:String + let rawMessage:String + let encryptedMessage:[String:String] + let signedMessages:[String:String] + let publicMarshaled:String + let privateMarshaled:String + } + + static let RSA_1024 = Fixture( + publicPEM: """ + +""", + privatePEM: """ +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANSRvSiXv+gtFt9s +upxbjfG0l2HvFD5V/nsNa2QSl5+Vnl9RMg0P6zUCVMC/rc2x9RfcYn+n7mOGeXfP +B5Mqvt7mFoxmo4loBFIqkbE4HDPUrduG8lb6LNfBSvA9tyaSICW+QCyOPWHBGk0P +y382i4X6E7ActAI++RfxgttTOhmvAgMBAAECgYAyjMnf+l5ft0FGNpQWFMunnBuX +5YP54vdWifVs4eL+x1TXM/bkFlIH1BsVjz+kt9oiJ32g/+1364W9URVrEPI8nk5i +Id40q3Qiozvn4ceWtSoCGmuxIbdRqL1JJn5e8Zfzs7E8KZimYu00t2qcidFDUsEC +biCqT14UNcbpwsOpkQJBAPxMogs3OnkgCWlptZckjg+srwxnXIkzDhSO+WaKl2Dm +DvSMnB2Ws64EDu2dP+HLiuoyqG/ZqRabdQqIsIrkLpkCQQDXr+wYGoOiL26PrAew +z49aH/wQZq8fBM2yuwvR+ZDRraQ0otQV1aRwffqlI+IfYowJvyPX+EC/ftcff0qa +6R+HAkAQZlrSJ9DhNrfl5j0rifDCDBOE1uMo9+yeYXzMsY2NeubV9p3fPoCHezQN +Nf+FCdoJxykzvA5Fre05thDjtllhAkEAgdsf2M81y1KlTQi0xKXiV8+D8dfwvUsm +EOJ+Vlfb8fGKOEqER/UNgNDIM96ryFuLll6m1ONZEDHskMERiLysRwJAawkNDlqe +sIjqrfR2luw+TLHkMI0T6pTY9s+79F9VVV/V13v2qtTpXw1eu7Sw+oDBpJoocz/h ++YzU+CyyzO+qUA== +-----END PRIVATE KEY----- +""", + rawMessage: "Hello RSA Signatures!", + encryptedMessage: [ + "algid:encrypt:RSA:raw": "N2T56NKkKAFdCytLP9zT0Iu9N0KNKkflB6vsNl6G+nkY/102laZLSbNZbdkzsOYSIml30ZaQSPS76aBuAYttlnCNEckgwmaS2IpHnFcUUFa/MOf+LJRcDXvkp+NoAmF0QFUhQ+VPfdineUrzOkL+xUi4hY614su6VdfPVmtJeog=", + "algid:encrypt:RSA:PKCS1": "uliKMjgMn54C/WmwagE0dHFrEKw9civz9YYkHS+KKdlqVeCf9qKrFoSHlpA1Mq4JFg0WmpLWaMxgBaD+1CrE4Y+k26+wa4JtffLbyabYrxJkNQ5Am99KnoZO8rLEp2VumxGcsWWseMgSqrlO9KTesD8sJGFCMiz6aSFieedjAu4=" + ], + signedMessages: [ + "algid:sign:RSA:raw" : "zpIDplKEdLvsHopjwoC36mQ3SRg2mZe/0RPP3DaDMnlSDLneoGwzR/L4oR/PTxD34wW7edQV4z5MrFSbmK4a7d+fwvNRQtwYlw/L04GTQyH8G6LhFUKL+++0jdPOMuMXADT8Yfrna6QHti2kqcUE4WSXHe6yY8xZZ6SHEDK71zg=", + "algid:sign:RSA:digest-PKCS1v15" : "s64/o2jeSm9OsTwlBuwJXOkJQPLoT300ZnMPDwfAdKsVFq8vR0uUDgkKYGnaogRu66QTWHfjSPcO2RUKV23141GM6Tng3zv3WGQm2Eg663n+9tYpsV5hCussJAcAwuGHoZwFV79alpNZkFyHEjya189zPeT1K3FbZJniL0ykTuk=", + "algid:sign:RSA:digest-PKCS1v15:SHA1" : "zIqv0mqhlDl0pf/Z5cRuZSP8oskOJhwluNI9EJRBC8b3RXlPlj2BzZyNbN0Mys3joVlfEiw4YsKYKFWN3SwGSwsYfcfeWpDJ5vJF3s32JkXnfHLdspTeapeVYDSy4MS8mNkVbYB6pQFBNK6scfzUFY7pLPKzUJ1MCnRmwpc0MbU=", + "algid:sign:RSA:digest-PKCS1v15:SHA224" : "TS9eVlAFagKSmHtSdjunj3hgqQY5Zu7agjeYPvChB+jPgoqw/H3QwdzA4deZgcmsE1BooCgK9/1iekEWU/tjilVVrkhB5Kq5YxAWA7+IBo5pYFbmsAvP4ka+Oq1urfAYQbzTAuFyEXbdfXQATotElZFHwWjlTvZyk/IFfEawqtg=", + "algid:sign:RSA:digest-PKCS1v15:SHA256" : "bLshLiyA9r2aow0u3+UKTSnyght7+8MuxEFzKsQrKgi9wYNwXsZEToB7jZ6+Y/hbezdIYXHwdtkHmBslAQBEGk+njsggrtWPVSDu/yU6icjEiiEd/35tVzgFejhmhj/5b8odScLrJF+6IeDl4iv9/tQZ7znOGImg5nZSik9c6dI=", + "algid:sign:RSA:digest-PKCS1v15:SHA384" : "N810I+DcCYE7RROmKCHFl7MZl34dHkIx6Y3TxWv5g/JfvZHGRf+TwaFDjD7cGAdV+jY4wZd6mSNZvrhLgfb8t2X5JOaIiDaXt39etAywgE7OuMMYZsD596UBQFrdEu0bQIsK3+D+GcRCNYFVUUsJmYLvo/cio59IcTSRu1f3/5Y=", + "algid:sign:RSA:digest-PKCS1v15:SHA512" : "rvrbc/LRhgGbXq1yAybMxfejAf+GHi4bcrhNKMRtg+RT3iw+Z5KLKzcSWinD9yH1j8NrL8u7EPLNDQ6EGt8y0JYSk0KqwseBpC2/zicu2HTypzFLnrNDtAw6E1A+AVOoAPkxkKf8F/ledih4xKn884USD2jO4ncyoXK4sGj0sjA=", + "algid:sign:RSA:message-PKCS1v15:SHA1" : "BMmnNyAMr8CMYpiZJAngT1o7wDGB1+hrHBHCs5OLcM/bpzqJ8+L9hHnWBeh4hZGcIkRCnB5KFd42WwcNLUQi1EUQHvDDH9gwpT8oPWn7Y/bkflwtKl9A3R1RiobY2rafe5PlbKW+SlN8ddZ0gevt5w7Ob+vQYRLu+e5dSSxVrtY=", + "algid:sign:RSA:message-PKCS1v15:SHA224": "Ro+Y9+TavJt18Bin3+WVVg3YOzPsIlky7LiPXkMdsh1Zq5j3CD23EehNIG2HT3QXSG2ySZuaEj0swJvJWEvcmc1lo8f0xONkgCSk8iKtRzoJ6AJe3abqwc2gNHofzUtJq/eh2ZCO/IFvXC0B4sMIf2ztJuSNRW9O8d0m8zCsHZo=", + "algid:sign:RSA:message-PKCS1v15:SHA256": "kaqP1oUrtRPUTA5uBAcPrIDGQPAqn8uH9pHMFYumS9FwZTYlRAeCFliMuiyW79x+x+BOC6TX+mipXgWJIO1IaucyrLBKlak934SX6q71xWA74SSYlMEzalKPFpi879fvgGyY4fRypJQv5uZ3nvlvxAhyB/pX7jaV07ct9sKIQv4=", + "algid:sign:RSA:message-PKCS1v15:SHA384": "hxsA7RjGU97s1erJAv1WTkscZk61NHv55s0BWHoJEXgda0WulbcnOQduZJWeSyxJjRh4kGztV42xOvMpo9qcovbYOI3hQJ210gbNTBKmTp9tG79ShV6lx07eceC2XZg9kYxtgkuSpurRjd2PFbkGFGhTZmqRaSQukPjSIhnxoyQ=", + "algid:sign:RSA:message-PKCS1v15:SHA512": "r31GD74cN5wknycZDyNZdJ4HJBBLv5zMH+dmfYW98i3szDS8txdr0M8ZrmM0jLxcSpwa5461vwMBhyCOYlqY2y3HoKNolIDSANhWPufKFMcv+ob3okNDQGXOAyPKhxn/EW7X2Mz3XQlBnOA6c18KR3UnZvoW5wn9K1tpv4ueEyI=" + ], + publicMarshaled: "CAASogEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANSRvSiXv+gtFt9supxbjfG0l2HvFD5V/nsNa2QSl5+Vnl9RMg0P6zUCVMC/rc2x9RfcYn+n7mOGeXfPB5Mqvt7mFoxmo4loBFIqkbE4HDPUrduG8lb6LNfBSvA9tyaSICW+QCyOPWHBGk0Py382i4X6E7ActAI++RfxgttTOhmvAgMBAAE=", + privateMarshaled: "CAAS4AQwggJcAgEAAoGBANSRvSiXv+gtFt9supxbjfG0l2HvFD5V/nsNa2QSl5+Vnl9RMg0P6zUCVMC/rc2x9RfcYn+n7mOGeXfPB5Mqvt7mFoxmo4loBFIqkbE4HDPUrduG8lb6LNfBSvA9tyaSICW+QCyOPWHBGk0Py382i4X6E7ActAI++RfxgttTOhmvAgMBAAECgYAyjMnf+l5ft0FGNpQWFMunnBuX5YP54vdWifVs4eL+x1TXM/bkFlIH1BsVjz+kt9oiJ32g/+1364W9URVrEPI8nk5iId40q3Qiozvn4ceWtSoCGmuxIbdRqL1JJn5e8Zfzs7E8KZimYu00t2qcidFDUsECbiCqT14UNcbpwsOpkQJBAPxMogs3OnkgCWlptZckjg+srwxnXIkzDhSO+WaKl2DmDvSMnB2Ws64EDu2dP+HLiuoyqG/ZqRabdQqIsIrkLpkCQQDXr+wYGoOiL26PrAewz49aH/wQZq8fBM2yuwvR+ZDRraQ0otQV1aRwffqlI+IfYowJvyPX+EC/ftcff0qa6R+HAkAQZlrSJ9DhNrfl5j0rifDCDBOE1uMo9+yeYXzMsY2NeubV9p3fPoCHezQNNf+FCdoJxykzvA5Fre05thDjtllhAkEAgdsf2M81y1KlTQi0xKXiV8+D8dfwvUsmEOJ+Vlfb8fGKOEqER/UNgNDIM96ryFuLll6m1ONZEDHskMERiLysRwJAawkNDlqesIjqrfR2luw+TLHkMI0T6pTY9s+79F9VVV/V13v2qtTpXw1eu7Sw+oDBpJoocz/h+YzU+CyyzO+qUA==" + ) +} + + +//func testRSAPEMImportSignAndVerify() throws { +// let expectedSignature: Array = [ +// 0x76, 0xEB, 0x7F, 0x10, 0x95, 0x40, 0xC9, 0x19, 0xE6, 0x44, 0x6F, 0xCD, 0x88, 0x83, 0x22, 0x6E, +// 0x5C, 0xE4, 0x1E, 0x87, 0xE3, 0xAF, 0x3B, 0x59, 0xB7, 0xB2, 0x89, 0xFD, 0x88, 0x37, 0xC0, 0xCE, +// 0xEA, 0x0E, 0x87, 0x06, 0x5F, 0x6E, 0xE7, 0x8C, 0xE9, 0x3F, 0xD6, 0xC3, 0xE0, 0x0B, 0x94, 0x19, +// 0xAC, 0x58, 0x2D, 0x73, 0xD3, 0x92, 0x45, 0x2C, 0x66, 0x7F, 0xB5, 0x24, 0xC6, 0xEA, 0xC6, 0xE2, +// 0x0E, 0xBB, 0x12, 0x86, 0x5B, 0xF4, 0x1D, 0x25, 0x2F, 0x68, 0x69, 0x30, 0x80, 0x4D, 0x10, 0xDF, +// 0x25, 0x5E, 0x00, 0x1D, 0x2F, 0x5F, 0x67, 0xE5, 0x4C, 0x7D, 0x1E, 0x64, 0xB2, 0x0B, 0xE8, 0x19, +// 0xE6, 0xB8, 0x62, 0xA6, 0xD1, 0x66, 0x58, 0x47, 0xAC, 0xAB, 0xAB, 0xCD, 0x26, 0x3D, 0x16, 0x52, +// 0xBF, 0x35, 0xB0, 0x21, 0xE2, 0xE3, 0x48, 0x77, 0x1E, 0x81, 0xE8, 0xCF, 0x75, 0x67, 0x64, 0x2A +// ] +// +// let message = "Hello RSA Signatures!".data(using: .utf8)! +// +// let keyPair = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.RSA_1024_PRIVATE) +// +// let secKey = try initSecKey(rawRepresentation: keyPair.privateKey!.rawRepresentation) +// +// let privateMarshaled = try keyPair.privateKey?.marshal() +// print(privateMarshaled!.asString(base: .base64Pad)) +// +// let publicMarsheled = try keyPair.marshalPublicKey() +// print(publicMarsheled.asString(base: .base64Pad)) +// +// let pemData = try secKey.extractPubKey().rawRepresentation() +// +// let pem = "-----BEGIN PUBLIC KEY-----\n" + pemData.asString(base: .base64Pad).split(intoChunksOfLength: 64).joined(separator: "\n") + "\n-----END PUBLIC KEY-----" +// +// print(pem) +// +// try sign(message: message, using: secKey)//keyPair.sign(message: message) +// +// try encrypt(data: message, with: secKey.extractPubKey()) +// +//// printHexData16BytesWide(signature.bytes) +//// print(signature.asString(base: .base64Pad)) +//// +//// XCTAssertEqual(signature.bytes, expectedSignature) +//} + +//private func printHexData16BytesWide(_ bytes:[UInt8]) { +// print(bytes.toHexString().split(intoChunksOfLength: 32).map { $0.split(intoChunksOfLength: 2).map { "0x\($0.uppercased())" }.joined(separator: ", ") }.joined(separator: ",\n")) +//} +// +//private func initSecKey(rawRepresentation raw: Data) throws -> SecKey { +// let attributes: [String:Any] = [ +// kSecAttrKeyType as String: kSecAttrKeyTypeRSA, +// kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, +// kSecAttrKeySizeInBits as String: 1024, +// kSecAttrIsPermanent as String: false +// ] +// +// var error:Unmanaged? = nil +// guard let secKey = SecKeyCreateWithData(raw as CFData, attributes as CFDictionary, &error) else { +// throw NSError(domain: "Error constructing SecKey from raw key data: \(error.debugDescription)", code: 0, userInfo: nil) +// } +// +// return secKey +//} + +//private func sign(message: Data, using key: SecKey) throws { +// let algorithms:[SecKeyAlgorithm] = [ +// .rsaSignatureRaw, +// //.rsaSignatureDigestPSSSHA1, +// //.rsaSignatureDigestPSSSHA224, +// //.rsaSignatureDigestPSSSHA256, +// //.rsaSignatureDigestPSSSHA384, +// //.rsaSignatureDigestPSSSHA512, +// .rsaSignatureDigestPKCS1v15Raw, +// .rsaSignatureDigestPKCS1v15SHA1, +// .rsaSignatureDigestPKCS1v15SHA224, +// .rsaSignatureDigestPKCS1v15SHA256, +// .rsaSignatureDigestPKCS1v15SHA384, +// .rsaSignatureDigestPKCS1v15SHA512, +// //.rsaSignatureMessagePSSSHA1, +// //.rsaSignatureMessagePSSSHA224, +// //.rsaSignatureMessagePSSSHA256, +// //.rsaSignatureMessagePSSSHA384, +// //.rsaSignatureMessagePSSSHA512, +// .rsaSignatureMessagePKCS1v15SHA1, +// .rsaSignatureMessagePKCS1v15SHA224, +// .rsaSignatureMessagePKCS1v15SHA256, +// .rsaSignatureMessagePKCS1v15SHA384, +// .rsaSignatureMessagePKCS1v15SHA512, +// ] +// +// for algo in algorithms { +// var error: Unmanaged? +// +// // Sign the data +// guard let signature = SecKeyCreateSignature( +// key, +// algo, +// message as CFData, +// &error) as Data? +// else { print("\"\(algo.rawValue)\": \"nil\","); continue } +// +// // Throw the error if we encountered one +// if let error = error { print("\"\(algo.rawValue)\": \"\(error.takeRetainedValue())\","); continue } +// +// // Return the signature +// print("\"\(algo.rawValue)\": \"\(signature.asString(base: .base64Pad))\",") +// } +// +//} + +//private func encrypt(data: Data, with key:SecKey) throws { +// let algorithms:[SecKeyAlgorithm] = [ +// .rsaEncryptionRaw, +// .rsaEncryptionPKCS1 +// ] +// +// for algo in algorithms { +// var error:Unmanaged? +// guard let encryptedData = SecKeyCreateEncryptedData(key, .rsaEncryptionPKCS1, data as CFData, &error) else { +// print("\"\(algo.rawValue)\": \"\(error?.takeRetainedValue().localizedDescription ?? "nil")\","); continue +// } +// print("\"\(algo.rawValue)\": \"\((encryptedData as Data).asString(base: .base64Pad))\",") +// } +//} From d740f468b645b98d06c1cc34d1f075a87be7fc39 Mon Sep 17 00:00:00 2001 From: Brandon Date: Mon, 6 Jun 2022 19:23:08 -0700 Subject: [PATCH 17/52] Updated tests to use the KeyPair(pem:) initializer instead of the parsePem function. Added some additional tests. Moved the old EC keys to the bottom of the file. --- .../LibP2PCryptoTests/LibP2PCryptoTests.swift | 3027 ++++++++--------- 1 file changed, 1467 insertions(+), 1560 deletions(-) diff --git a/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift b/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift index a51b2df..1bdf6e0 100644 --- a/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift +++ b/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift @@ -30,6 +30,7 @@ final class libp2p_cryptoTests: XCTestCase { XCTAssertEqual(attributes?.isPrivate, true) } + /// These tests are skipped on Linux when using CryptoSwift due to very slow key generation times. #if canImport(Security) func testRSA2048() throws { let keyPair = try LibP2PCrypto.Keys.generateKeyPair(.RSA(bits: .B2048)) @@ -208,54 +209,6 @@ final class libp2p_cryptoTests: XCTestCase { XCTAssertEqual(pubKey.data, keyPair.publicKey.data) } -// /// Eliptic Curves -// func testEC256() throws { -// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.EC(curve: .P256)) -// print(keyPair) -// } -// -// func testEC256KeyPair() throws { -// let keyPair = try LibP2PCrypto.Keys.generateKeyPair(.EC(curve: .P256)) -// XCTAssertFalse(keyPair.publicKey.isRSAKey) -// XCTAssertTrue(keyPair.publicKey.isPublicKey) -// XCTAssertFalse(keyPair.privateKey.isPublicKey) -// } -// -// func testECDSA256() throws { -// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.ECDSA(curve: .P256)) -// print(keyPair) -// } -// -// func testECDSA384() throws { -// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.ECDSA(curve: .P384)) -// print(keyPair) -// } -// -// func testECDSA521() throws { -// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.ECDSA(curve: .P521)) -// print(keyPair) -// } -// -// func testECSecPrimeRandom() throws { -// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.ECSECPrimeRandom()) -// print(keyPair) -// } - -// func testEphemeralMashallingRoundTrip() throws { -// let keyPair = try LibP2PCrypto.Keys.generateRawEphemeralKeyPair(curve: .P256) -// -// print("Public Key: \(keyPair.publicKey.asString(base: .base16))") -// -// let marshaledPubKey = try LibP2PCrypto.Keys.marshalPublicKey(raw: keyPair.publicKey, keyType: .ECDSA(curve: .P256)) -// print("Marshaled PubKey Bytes: \(marshaledPubKey)") -// -// let unmarshaledPubKey = try LibP2PCrypto.Keys.unmarshalPublicKey(buf: marshaledPubKey, into: .base16) -// -// print("Public Key: \(unmarshaledPubKey)") -// XCTAssertEqual(unmarshaledPubKey, keyPair.publicKey.asString(base: .base16)) -// } -// - // - MARK: Marshaling // Manual @@ -334,7 +287,7 @@ final class libp2p_cryptoTests: XCTestCase { print(privKey) } - func testImportFromMarshalledPrivateKey() throws { + func testImportFromMarshalledPrivateKey_1024() throws { let keyPair = try LibP2PCrypto.Keys.KeyPair(marshaledPrivateKey: MarshaledData.PRIVATE_RSA_KEY_1024, base: .base64Pad) //RawPrivateKey(marshaledKey: MarshaledData.PRIVATE_KEY, base: .base64Pad) print(keyPair) @@ -342,14 +295,101 @@ final class libp2p_cryptoTests: XCTestCase { XCTAssertNotNil(keyPair.privateKey) XCTAssertNotNil(keyPair.publicKey) XCTAssertEqual(keyPair.keyType, .rsa) + XCTAssertTrue(keyPair.hasPrivateKey) + + /// Ensure that when we marshal the private key, we end up with that same data we imported. + XCTAssertEqual(try keyPair.privateKey?.marshal().asString(base: .base64Pad), MarshaledData.PRIVATE_RSA_KEY_1024) - /// Ensures that the private key was instantiated properly and then we can derive the public key from it and then marshal it + /// Ensures that the public key derived from the private key is correct and the marshaled version matches that of the fixture. XCTAssertEqual(try keyPair.publicKey.marshal().asString(base: .base64Pad), MarshaledData.PUBLIC_RSA_KEY_1024) } + + func testImportFromMarshalledPrivateKey_2048() throws { + let keyPair = try LibP2PCrypto.Keys.KeyPair(marshaledPrivateKey: MarshaledData.PRIVATE_RSA_KEY_2048, base: .base64Pad) //RawPrivateKey(marshaledKey: MarshaledData.PRIVATE_KEY, base: .base64Pad) + + print(keyPair) + + XCTAssertNotNil(keyPair.privateKey) + XCTAssertNotNil(keyPair.publicKey) + XCTAssertEqual(keyPair.keyType, .rsa) + XCTAssertTrue(keyPair.hasPrivateKey) + + /// Ensure that when we marshal the private key, we end up with that same data we imported. + XCTAssertEqual(try keyPair.privateKey?.marshal().asString(base: .base64Pad), MarshaledData.PRIVATE_RSA_KEY_2048) + + /// Ensures that the public key derived from the private key is correct and the marshaled version matches that of the fixture. + XCTAssertEqual(try keyPair.publicKey.marshal().asString(base: .base64Pad), MarshaledData.PUBLIC_RSA_KEY_2048) + } + + func testImportFromMarshalledPrivateKey_3072() throws { + let keyPair = try LibP2PCrypto.Keys.KeyPair(marshaledPrivateKey: MarshaledData.PRIVATE_RSA_KEY_3072, base: .base64Pad) //RawPrivateKey(marshaledKey: MarshaledData.PRIVATE_KEY, base: .base64Pad) + + print(keyPair) + + XCTAssertNotNil(keyPair.privateKey) + XCTAssertNotNil(keyPair.publicKey) + XCTAssertEqual(keyPair.keyType, .rsa) + XCTAssertTrue(keyPair.hasPrivateKey) + + /// Ensure that when we marshal the private key, we end up with that same data we imported. + XCTAssertEqual(try keyPair.privateKey?.marshal().asString(base: .base64Pad), MarshaledData.PRIVATE_RSA_KEY_3072) + + /// Ensures that the public key derived from the private key is correct and the marshaled version matches that of the fixture. + XCTAssertEqual(try keyPair.publicKey.marshal().asString(base: .base64Pad), MarshaledData.PUBLIC_RSA_KEY_3072) + } + + func testImportFromMarshalledPrivateKey_4096() throws { + let keyPair = try LibP2PCrypto.Keys.KeyPair(marshaledPrivateKey: MarshaledData.PRIVATE_RSA_KEY_4096, base: .base64Pad) //RawPrivateKey(marshaledKey: MarshaledData.PRIVATE_KEY, base: .base64Pad) + + print(keyPair) + + XCTAssertNotNil(keyPair.privateKey) + XCTAssertNotNil(keyPair.publicKey) + XCTAssertEqual(keyPair.keyType, .rsa) + XCTAssertTrue(keyPair.hasPrivateKey) + + /// Ensure that when we marshal the private key, we end up with that same data we imported. + XCTAssertEqual(try keyPair.privateKey?.marshal().asString(base: .base64Pad), MarshaledData.PRIVATE_RSA_KEY_4096) + + /// Ensures that the public key derived from the private key is correct and the marshaled version matches that of the fixture. + XCTAssertEqual(try keyPair.publicKey.marshal().asString(base: .base64Pad), MarshaledData.PUBLIC_RSA_KEY_4096) + } // - MARK: SIGN & VERIFY - func testRSAMessageSignVerify() throws { + func testRSAMessageSignVerify_StaticKey() throws { + let message = TestFixtures.RSA_1024.rawMessage.data(using: .utf8)! + + let rsa = try LibP2PCrypto.Keys.KeyPair(marshaledPrivateKey: TestFixtures.RSA_1024.privateMarshaled, base: .base64Pad) + + let signedData = try rsa.privateKey!.sign(message: message) + + print(signedData.asString(base: .base64Pad)) + + XCTAssertEqual(signedData.asString(base: .base64Pad), TestFixtures.RSA_1024.signedMessages["algid:sign:RSA:message-PKCS1v15:SHA256"]) + XCTAssertNotEqual(message, signedData) + + // This just ensures that a newly instantiated Pub SecKey matches the derived pubkey from the keypair... + let recoveredPubKey:RSAPublicKey = try RSAPublicKey(rawRepresentation: rsa.publicKey.data) + XCTAssertEqual(rsa.publicKey.data, recoveredPubKey.rawRepresentation) + XCTAssertEqual(try rsa.marshalPublicKey().asString(base: .base64Pad), TestFixtures.RSA_1024.publicMarshaled) + + // Ensure the rsaSignatureMessagePKCS1v15SHA256 algorithm works with our RSA KeyPair + //XCTAssertTrue(SecKeyIsAlgorithmSupported(recoveredPubKey, .verify, .rsaSignatureMessagePKCS1v15SHA256)) + + // Ensure the Signed Data is Valid for the given message + XCTAssertTrue(try rsa.publicKey.verify(signature: signedData, for: message)) + + // Ensure that the signature is no longer valid if it is tweaked in any way + XCTAssertThrowsError(try rsa.publicKey.verify(signature: Data(signedData.shuffled()), for: message)) + XCTAssertThrowsError(try rsa.publicKey.verify(signature: Data(signedData.dropFirst()), for: message)) + + // Ensure that the signature is no longer valid if the message is tweaked in any way + XCTAssertThrowsError(try rsa.publicKey.verify(signature: signedData, for: Data(message.shuffled()))) + XCTAssertThrowsError(try rsa.publicKey.verify(signature: signedData, for: Data(message.dropFirst()))) + } + + func testRSAMessageSignVerify_DynamicKey() throws { let message = "Hello, swift-libp2p-crypto!".data(using: .utf8)! let rsa = try LibP2PCrypto.Keys.generateKeyPair(.RSA(bits: .B1024)) @@ -575,1641 +615,1508 @@ final class libp2p_cryptoTests: XCTestCase { // print(keyPair) // } - /// RSA Object Identifier --> 2a 86 48 86 f7 0d 01 01 01 (bit length independent, pub/priv key independent) - /// ECDSA P384 --> 2a 86 48 ce 3d 02 01 -// func testPemParsing() throws { -// -//// let pem = """ -//// -----BEGIN PUBLIC KEY----- -//// MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcZ/r0nvJyHUUstIB5BqCUJ1CC -//// Cd1nzle4bEpPQJ/S0Wn7mV2FDAeh+UcbVhZu9n+5zypYNjeZKapPqBLoT8eCK51y -//// Kpzeb8LuEm3P8PK4xN18XBrIF1GprN8IIgSdK9f5SwnemutcURrY+PlWnvj7N5s/ -//// 03RlJA3/NHVXpPW/VQIDAQAB -//// -----END PUBLIC KEY----- -//// """ -// -// let pem = """ -// -----BEGIN PRIVATE KEY----- -// MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQDp0Whyqa8KmdvK -// 0MsQGJEBzDAEHAZc0C6cr0rkb6Xwo+yB5kjZBRDORk0UXtYGE1pYt4JhUTmMzcWO -// v2xTIsdbVMQlNtput2U8kIqS1cSTkX5HxOJtCiIzntMzuR/bGPSOexkyFQ8nCUqb -// ROS7cln/ixprra2KMAKldCApN3ue2jo/JI1gyoS8sekhOASAa0ufMPpC+f70sc75 -// Y53VLnGBNM43iM/2lsK+GI2a13d6rRy86CEM/ygnh/EDlyNDxo+SQmy6GmSv/lmR -// xgWQE2dIfK504KIxFTOphPAQAr9AsmcNnCQLhbz7YTsBz8WcytHGQ0Z5pnBQJ9AV -// CX9E6DFHetvs0CNLVw1iEO06QStzHulmNEI/3P8I1TIxViuESJxSu3pSNwG1bSJZ -// +Qee24vvlz/slBzK5gZWHvdm46v7vl5z7SA+whncEtjrswd8vkJk9fI/YTUbgOC0 -// HWMdc2t/LTZDZ+LUSZ/b2n5trvdJSsOKTjEfuf0wICC08pUUk8MCAwEAAQKCAYEA -// ywve+DQCneIezHGk5cVvp2/6ApeTruXalJZlIxsRr3eq2uNwP4X2oirKpPX2RjBo -// NMKnpnsyzuOiu+Pf3hJFrTpfWzHXXm5Eq+OZcwnQO5YNY6XGO4qhSNKT9ka9Mzbo -// qRKdPrCrB+s5rryVJXKYVSInP3sDSQ2IPsYpZ6GW6Mv56PuFCpjTzElzejV7M0n5 -// 0bRmn+MZVMVUR54KYiaCywFgUzmr3yfs1cfcsKqMRywt2J58lRy/chTLZ6LILQMv -// 4V01neVJiRkTmUfIWvc1ENIFM9QJlky9AvA5ASvwTTRz8yOnxoOXE/y4OVyOePjT -// cz9eumu9N5dPuUIMmsYlXmRNaeGZPD9bIgKY5zOlfhlfZSuOLNH6EHBNr6JAgfwL -// pdP43sbg2SSNKpBZ0iSMvpyTpbigbe3OyhnFH/TyhcC2Wdf62S9/FRsvjlRPbakW -// YhKAA2kmJoydcUDO5ccEga8b7NxCdhRiczbiU2cj70pMIuOhDlGAznyxsYbtyxaB -// AoHBAPy6Cbt6y1AmuId/HYfvms6i8B+/frD1CKyn+sUDkPf81xSHV7RcNrJi1S1c -// V55I0y96HulsR+GmcAW1DF3qivWkdsd/b4mVkizd/zJm3/Dm8p8QOnNTtdWvYoEB -// VzfAhBGaR/xflSLxZh2WE8ZHQ3IcRCXV9ZFgJ7PMeTprBJXzl0lTptvrHyo9QK1v -// obLrL/KuXWS0ql1uSnJr1vtDI5uW8WU4GDENeU5b/CJHpKpjVxlGg+7pmLknxlBl -// oBnZnQKBwQDs2Ky29qZ69qnPWowKceMJ53Z6uoUeSffRZ7xuBjowpkylasEROjuL -// nyAihIYB7fd7R74CnRVYLI+O2qXfNKJ8HN+TgcWv8LudkRcnZDSvoyPEJAPyZGfr -// olRCXD3caqtarlZO7vXSAl09C6HcL2KZ8FuPIEsuO0Aw25nESMg9eVMaIC6s2eSU -// NUt6xfZw1JC0c+f0LrGuFSjxT2Dr5WKND9ageI6afuauMuosjrrOMl2g0dMcSnVz -// KrtYa7Wi1N8CgcBFnuJreUplDCWtfgEen40f+5b2yAQYr4fyOFxGxdK73jVJ/HbW -// wsh2n+9mDZg9jIZQ/+1gFGpA6V7W06dSf/hD70ihcKPDXSbloUpaEikC7jxMQWY4 -// uwjOkwAp1bq3Kxu21a+bAKHO/H1LDTrpVlxoJQ1I9wYtRDXrvBpxU2XyASbeFmNT -// FhSByFn27Ve4OD3/NrWXtoVwM5/ioX6ZvUcj55McdTWE3ddbFNACiYX9QlyOI/TY -// bhWafDCPmU9fj6kCgcEAjyQEfi9jPj2FM0RODqH1zS6OdG31tfCOTYicYQJyeKSI -// /hAezwKaqi9phHMDancfcupQ89Nr6vZDbNrIFLYC3W+1z7hGeabMPNZLYAs3rE60 -// dv4tRHlaNRbORazp1iTBmvRyRRI2js3O++3jzOb2eILDUyT5St+UU/LkY7R5EG4a -// w1df3idx9gCftXufDWHqcqT6MqFl0QgIzo5izS68+PPxitpRlR3M3Mr4rCU20Rev -// blphdF+rzAavYyj1hYuRAoHBANmxwbq+QqsJ19SmeGMvfhXj+T7fNZQFh2F0xwb2 -// rMlf4Ejsnx97KpCLUkoydqAs2q0Ws9Nkx2VEVx5KfUD7fWhgbpdnEPnQkfeXv9sD -// vZTuAoqInN1+vj1TME6EKR/6D4OtQygSNpecv23EuqEvyXWqRVsRt9Qd2B0H4k7h -// gnjREs10u7zyqBIZH7KYVgyh27WxLr859ap8cKAH6Fb+UOPtZo3sUeeume60aebn -// 4pMwXeXP+LO8NIfRXV8mgrm86g== -// -----END PRIVATE KEY----- -// """ -// -//// /// EC P256 Public Key -//// let pem = """ -//// -----BEGIN PUBLIC KEY----- -//// MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEb4nB0k8CBVnKCHVHkxuXAkSlZuO5 -//// Nsev1rzcRv5QHiJuWUKomFGadQlMSGwoDOHEDdW3ujcA6t0ADteHw6KrZg== -//// -----END PUBLIC KEY----- -//// """ -// -//// /// EC P384 Public Key -//// let pem = """ -//// -----BEGIN PUBLIC KEY----- -//// MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEBwY0l7mq7hSBEZRld5ISWfSoFsYN3wwM -//// hdD3cMU95DmYXzbqVHB4dCfsy7bexm4h9c0zs4CyTPzy3DV3vfmv1akQJIQv7l08 -//// lx/YXNeGXTN4Gr9r4rwA5GvRl1p6plPL -//// -----END PUBLIC KEY----- -//// """ -// -//// /// EC P521 Public Key -//// let pem = """ -//// -----BEGIN PUBLIC KEY----- -//// MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAp3v1UQWvSyQnkAUEBu+x/7ZrPtNJ -//// SCUk9kMvuZMyGP1idwvspALuJjzrSFFlXObjlOjxucSbWhTYF/o3nc0XzpAA3dxA -//// BYiMqH9vrVePoJMpv+DMdkUiUJ/WqHSOu9bJEi1h4fdqh5HHx4QZJY/iX/59VAi1 -//// uSbAhALvbdGFbVpkcOs= -//// -----END PUBLIC KEY----- -//// """ -// -// /// EC P256 Private Key -//// let pem = """ -//// -----BEGIN PRIVATE KEY----- -//// MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgZjQLlzempZx7YF1F -//// +MK1HWZTNgLcC1MAufb/2/YZYk6hRANCAAQwgn0PfkIHiZ/K+3zA//CoDqU2PqDc -//// aA3U5R68jmlZQITvMyBlMJl9Mjh0biIe88dAfRKeUm9FVMD2ErJ/006V -//// -----END PRIVATE KEY----- -//// """ -// -// /// PEMP384PKCS8 -//// let pem = """ -//// -----BEGIN PRIVATE KEY----- -//// MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDB7ERKhMR+mvz1NQ+oL -//// i6ZJMACOcwbUetWcNnB4Mnx3j4XuhpkkHEW8E1+rXyjZ3UmhZANiAASYH+emlyXM -//// kBSFJl0BiopDVuIIR47M4pLl00YNnuu/Rp5VHeVAHrP67i2Q92u5fk34eOSwQvkO -//// VvktWsgtzAomIam4SHqE9bhvrHy6kW6QzxlERHTL+YkXEX8c6t8VOxk= -//// -----END PRIVATE KEY----- -//// """ -// -// let chunks = pem.split(separator: "\n") -// guard chunks.count > 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } -// -// //print("Attempting to decode: \(chunks[1.. 32 { + privKeyData.removeFirst() + } + + print(privKeyData.count) + + let privKey = try Curve25519.Signing.PrivateKey(rawRepresentation: privKeyData.bytes) + + print(privKey) + + XCTAssertEqual("CM3Nzttt7KmXG9qDEYys++oQ9G749jqrbRRs92BUzpA=", privKey.publicKey.rawRepresentation.asString(base: .base64Pad)) + + } + + func testED25519PemImport_Private() throws { + let pem = """ + -----BEGIN PRIVATE KEY----- + MC4CAQAwBQYDK2VwBCIEIOkK9EOHRqD5QueUrMZbia55UWpokoFpWco4r2GnRVZ+ + -----END PRIVATE KEY----- + """ + + let keyPair = try LibP2PCrypto.Keys.KeyPair(pem: pem) + + print(keyPair) + XCTAssert(keyPair.keyType == .ed25519) + XCTAssertNotNil(keyPair.privateKey) + XCTAssertEqual(keyPair.publicKey.asString(base: .base64Pad), "CM3Nzttt7KmXG9qDEYys++oQ9G749jqrbRRs92BUzpA=") + } + + + func testSecp256k1PemImport_Public_Manual() throws { + let pem = """ + -----BEGIN PUBLIC KEY----- + MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzw + xDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== + -----END PUBLIC KEY----- + """ + + let (_, bytes, _) = try PEM.pemToData(pem.bytes) + + let asn = try ASN1.Decoder.decode(data: Data(bytes)) + + print(asn) + +// sequence(nodes: [ +// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 7 bytes), :id-ecPublicKey +// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 5 bytes) :secp256k1 +// ]), +// libp2p_crypto.Asn1Parser.Node.bitString(data: 65 bytes) +// ]) + + guard case .sequence(let top) = asn, case .bitString(let pubKeyData) = top.last else { + return XCTFail("Failed to extract our Public Key bit/octet string") + } + + let pubKey = try Secp256k1PublicKey(pubKeyData.bytes) + + print(pubKey) + + XCTAssertEqual(pubKey.rawPublicKey.asString(base: .base64Pad), "IgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w==") + XCTAssertEqual(pubKey.rawRepresentation, try LibP2PCrypto.Keys.KeyPair(pem: pem).publicKey.rawRepresentation) + } + + func testSecp256k1PemImport_Public() throws { + let pem = """ + -----BEGIN PUBLIC KEY----- + MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzw + xDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== + -----END PUBLIC KEY----- + """ + + let keyPair = try LibP2PCrypto.Keys.KeyPair(pem: pem) + + print(keyPair) + XCTAssert(keyPair.keyType == .secp256k1) + XCTAssertNil(keyPair.privateKey) + print(keyPair.attributes() ?? "NIL") + } + + func testSecp256k1PemImport_Private_Manual() throws { + let pem = """ + -----BEGIN EC PRIVATE KEY----- + MHQCAQEEIJmbpwD3mZhlEtiGzmgropJ/nSewc8UPyBE9wib742saoAcGBSuBBAAK + oUQDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwf + X7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== + -----END EC PRIVATE KEY----- + """ + + let (_, bytes, _) = try PEM.pemToData(pem.bytes) + + let asn = try ASN1.Decoder.decode(data: Data(bytes)) + + print(asn) + +// sequence(nodes: [ +// libp2p_crypto.Asn1ParserECPrivate.Node.integer(data: 1 bytes), +// libp2p_crypto.Asn1ParserECPrivate.Node.octetString(data: 32 bytes), // private key data +// libp2p_crypto.Asn1ParserECPrivate.Node.objectIdentifier(data: 7 bytes), :secp256k1 +// libp2p_crypto.Asn1ParserECPrivate.Node.bitString(data: 67 bytes) +// ]) + + guard case .sequence(let top) = asn, case .octetString(let privKeyData) = top[1] else { + return XCTFail("Failed to extract our PrivKey bit/octet string") + } + + let privKey = try Secp256k1PrivateKey(privKeyData.bytes) + + XCTAssertEqual(privKey.rawRepresentation.asString(base: .base64Pad), "mZunAPeZmGUS2IbOaCuikn+dJ7BzxQ/IET3CJvvjaxo=") + + /// Assert that we can derive the public from the private key + XCTAssertEqual("IgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w==", privKey.publicKey.rawPublicKey.asString(base: .base64Pad)) + XCTAssertEqual(privKey.rawRepresentation, try LibP2PCrypto.Keys.KeyPair(pem: pem).privateKey?.rawRepresentation) + XCTAssertEqual(privKey.publicKey.rawRepresentation, try LibP2PCrypto.Keys.KeyPair(pem: pem).publicKey.rawRepresentation) + } + + func testSecp256k1PemImport_Private() throws { + let pem = """ + -----BEGIN EC PRIVATE KEY----- + MHQCAQEEIJmbpwD3mZhlEtiGzmgropJ/nSewc8UPyBE9wib742saoAcGBSuBBAAK + oUQDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwf + X7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== + -----END EC PRIVATE KEY----- + """ + + let keyPair = try LibP2PCrypto.Keys.KeyPair(pem: pem) + + print(keyPair) + XCTAssert(keyPair.keyType == .secp256k1) + XCTAssertNotNil(keyPair.privateKey) + XCTAssertEqual(keyPair.privateKey?.rawRepresentation.asString(base: .base64Pad), "mZunAPeZmGUS2IbOaCuikn+dJ7BzxQ/IET3CJvvjaxo=") + /// Assert that we can derive the public from the private key + XCTAssertEqual(keyPair.publicKey.asString(base: .base64Pad), "IgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w==") + } + + + + func testRSAEncryptedPrivateKeyPem() throws { + /* + * Generated with + * openssl genpkey -algorithm RSA + * -pkeyopt rsa_keygen_bits:1024 + * -pkeyopt rsa_keygen_pubexp:65537 + * -out foo.pem + * openssl pkcs8 -in foo.pem -topk8 -v2 aes-128-cbc -passout pass:mypassword + */ + let pem = """ + -----BEGIN ENCRYPTED PRIVATE KEY----- + MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIP5QK2RfqUl4CAggA + MB0GCWCGSAFlAwQBAgQQj3OyM9gnW2dd/eRHkxjGrgSCAoCpM5GZB0v27cxzZsGc + O4/xqgwB0c/bSJ6QogtYU2KVoc7ZNQ5q9jtzn3I4ONvneOkpm9arzYz0FWnJi2C3 + BPiF0D1NkfvjvMLv56bwiG2A1oBECacyAb2pXYeJY7SdtYKvcbgs3jx65uCm6TF2 + BylteH+n1ewTQN9DLfASp1n81Ajq9lQGaK03SN2MUtcAPp7N9gnxJrlmDGeqlPRs + KpQYRcot+kE6Ew8a5jAr7mAxwpqvr3SM4dMvADZmRQsM4Uc/9+YMUdI52DG87EWc + 0OUB+fnQ8jw4DZgOE9KKM5/QTWc3aEw/dzXr/YJsrv01oLazhqVHnEMG0Nfr0+DP + q+qac1AsCsOb71VxaRlRZcVEkEfAq3gidSPD93qmlDrCnmLYTilcLanXUepda7ez + qhjkHtpwBLN5xRZxOn3oUuLGjk8VRwfmFX+RIMYCyihjdmbEDYpNUVkQVYFGi/F/ + 1hxOyl9yhGdL0hb9pKHH10GGIgoqo4jSTLlb4ennihGMHCjehAjLdx/GKJkOWShy + V9hj8rAuYnRNb+tUW7ChXm1nLq14x9x1tX0ciVVn3ap/NoMkbFTr8M3pJ4bQlpAn + wCT2erYqwQtgSpOJcrFeph9TjIrNRVE7Zlmr7vayJrB/8/oPssVdhf82TXkna4fB + PcmO0YWLa117rfdeNM/Duy0ThSdTl39Qd+4FxqRZiHjbt+l0iSa/nOjTv1TZ/QqF + wqrO6EtcM45fbFJ1Y79o2ptC2D6MB4HKJq9WCt064/8zQCVx3XPbb3X8Z5o/6koy + ePGbz+UtSb9xczvqpRCOiFLh2MG1dUgWuHazjOtUcVWvilKnkjCMzZ9s1qG0sUDj + nPyn + -----END ENCRYPTED PRIVATE KEY----- + """ + + let keyPair = try LibP2PCrypto.Keys.KeyPair(pem: pem, password: "mypassword") + + XCTAssertEqual(keyPair.keyType, .rsa) + XCTAssertEqual(keyPair.hasPrivateKey, true) + } + + func testImportEncryptedPemKey() throws { + /* + * Generated with + * openssl genpkey -algorithm RSA + * -pkeyopt rsa_keygen_bits:1024 + * -pkeyopt rsa_keygen_pubexp:65537 + * -out foo.pem + * openssl pkcs8 -in foo.pem -topk8 -v2 des3 -passout pass:mypassword + */ + let pem = """ + -----BEGIN ENCRYPTED PRIVATE KEY----- + MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQISznrfHd+D58CAggA + MBQGCCqGSIb3DQMHBAhx0DnnUvDiHASCAoCceplm+Cmwlgvn4hNsv6e4c/S1iA7w + 2hU7Jt8JgRCIMWjP2FthXOAFLa2fD4g3qncYXcDAFBXNyoh25OgOwstO14YkxhDi + wG4TeppGUt9IlyyCol6Z4WhQs1TGm5OcD5xDta+zBXsBnlgmKLD5ZXPEYB+3v/Dg + SvM4sQz6NgkVHN52hchERsnknwSOghiK9mIBH0RZU5LgzlDy2VoBCiEPVdZ7m4F2 + dft5e82zFS58vwDeNN/0r7fC54TyJf/8k3q94+4Hp0mseZ67LR39cvnEKuDuFROm + kLPLekWt5R2NGdunSQlA79BkrNB1ADruO8hQOOHMO9Y3/gNPWLKk+qrfHcUni+w3 + Ofq+rdfakHRb8D6PUmsp3wQj6fSOwOyq3S50VwP4P02gKcZ1om1RvEzTbVMyL3sh + hZcVB3vViu3DO2/56wo29lPVTpj9bSYjw/CO5jNpPBab0B/Gv7JAR0z4Q8gn6OPy + qf+ddyW4Kcb6QUtMrYepghDthOiS3YJV/zCNdL3gTtVs5Ku9QwQ8FeM0/5oJZPlC + TxGuOFEJnYRWqIdByCP8mp/qXS5alSR4uoYQSd7vZG4vkhkPNSAwux/qK1IWfqiW + 3XlZzrbD//9IzFVqGRs4nRIFq85ULK0zAR57HEKIwGyn2brEJzrxpV6xsHBp+m4w + 6r0+PtwuWA0NauTCUzJ1biUdH8t0TgBL6YLaMjlrfU7JstH3TpcZzhJzsjfy0+zV + NT2TO3kSzXpQ5M2VjOoHPm2fqxD/js+ThDB3QLi4+C7HqakfiTY1lYzXl9/vayt6 + DUD29r9pYL9ErB9tYko2rat54EY7k7Ts6S5jf+8G7Zz234We1APhvqaG + -----END ENCRYPTED PRIVATE KEY----- + """ + + /// We don't support the DES3 Cipher yet + XCTAssertThrowsError(try LibP2PCrypto.Keys.KeyPair(pem: pem, password: "mypassword")) + } + + + // - MARK: Encrypted PEM Imports + + /// Tests importing encrypted PEM private key with a plaintext password + /// + /// To decrypt an encrypted private RSA key... + /// 1) Strip the headers of the PEM and base64 decode the data + /// 2) Parse the data via ASN1 looking for the encryption algo, salt, iv and itterations used, and the ciphertext (aka octet string) + /// 3) Derive the encryption key using PBKDF2 (sha1, salt and itterations) + /// 4) Use encryption key to instantiate the AES CBC Cipher along with the IV + /// 5) Decrypt the encrypted octet string + /// 6) The decrypted octet string can be ASN1 parsed again for the private key octet string + /// 7) This raw data can be used to instantiate a SecKey +// func testRSAEncryptedPrivateKeyPem2_Manual() throws { // -// /// This document defines what that is for Ed25519 private keys: -// /// https://tools.ietf.org/html/draft-ietf-curdle-pkix-10 -// /// -// /// What it says is that inside the OCTET STRING is another OCTET STRING for the private key data. The ASN.1 tag for OCTET STRING is 0x04, and the length of that string is 32 bytes (0x20 in hex). -// /// So in the above string the leading 0420 is the OCTET STRING tag and length. The remaining 32 bytes are the key itself. -// func testED25519PemImport_Private_Manual() throws { -// let pem = """ -// -----BEGIN PRIVATE KEY----- -// MC4CAQAwBQYDK2VwBCIEIOkK9EOHRqD5QueUrMZbia55UWpokoFpWco4r2GnRVZ+ -// -----END PRIVATE KEY----- -// """ +// // Generated with +// // openssl genpkey -algorithm RSA +// // -pkeyopt rsa_keygen_bits:1024 +// // -pkeyopt rsa_keygen_pubexp:65537 +// // -out foo.pem +// let unencryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.UNENCRYPTED // -// let data = try pemToData(pem) +// // Encrypted with +// // openssl pkcs8 -in foo.pem -topk8 -v2 aes-128-cbc -passout pass:mypassword +// let encryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.ENCRYPTED // -// let asn = try Asn1ParserECPrivate.parse(data: data) +// let asn = try Asn1Parser.parse(data: pemToData(encryptedPem)) // // print(asn) // //// sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.integer(data: 1 bytes), //// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 3 bytes)] -//// ), -//// libp2p_crypto.Asn1Parser.Node.octetString(data: 34 bytes) <- This is actually another octetString +//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //[42,134,72,134,247,13,1,5,13] +//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //PBKDF2 //[42,134,72,134,247,13,1,5,12] +//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +//// libp2p_crypto.Asn1Parser.Node.octetString(data: 8 bytes), //SALT +//// libp2p_crypto.Asn1Parser.Node.integer(data: 2 bytes) //ITTERATIONS +//// ]) +//// ]), +//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //des-ede3-cbc [96,134,72,1,101,3,4,1,2] +//// libp2p_crypto.Asn1Parser.Node.octetString(data: 16 bytes) //IV +//// ]) +//// ]) +//// ]), +//// libp2p_crypto.Asn1Parser.Node.octetString(data: 640 bytes) //// ]) // -// guard case .sequence(let top) = asn, case .octetString(var privKeyData) = top.last else { -// return XCTFail("Failed to extract our PrivKey bit string") +// var saltData:Data? = nil +// var ivData:Data? = nil +// var itterationsData:Int? = nil +// var ciphertextData:Data? = nil +// +// if case .sequence(let top) = asn { +// if case .sequence(let top1) = top.first { +// if case .sequence(let top2) = top1.last { +// if case .sequence(let top3) = top2.first { +// if case .sequence(let top4) = top3.last { +// if case .octetString(let salt) = top4.first { +// print("Found the salt: \(salt.asString(base: .base16))") +// saltData = salt +// } +// if case .integer(let int) = top4.last { +// print("Found the itterations: \(int.asString(base: .base16))") +// itterationsData = Int(int.asString(base: .base16), radix: 16) +// } +// } +// } +// if case .sequence(let bottom3) = top2.last { +// if case .octetString(let iv) = bottom3.last { +// print("Found the IV: \(iv.asString(base: .base16))") +// ivData = iv +// } +// } +// } +// } +// if case .octetString(let cipherText) = top.last { +// print("Found the ciphertext: \(cipherText.count)") +// ciphertextData = cipherText +// } // } // -// while privKeyData.count > 32 { -// privKeyData.removeFirst() +// // Ensure we have everything we need to proceed... +// guard let salt = saltData, let iv = ivData, let itterations = itterationsData, let ciphertext = ciphertextData else { +// return XCTFail("Failed to parse our pcks#8 key") // } // -// print(privKeyData.count) +// // Attempt to derive the aes encryption key from the password and salt +// // PBKDF2-SHA1 +// guard let key = PBKDF2.SHA1(password: "mypassword", salt: salt, keyByteCount: 16, rounds: itterations) else { +// return XCTFail("Failed to derive key from password and salt") +// } // -// let privKey = try Curve25519.Signing.PrivateKey(rawRepresentation: privKeyData.bytes) +// // This also works, but it is incredibly slow... +//// let key2 = try PKCS5.PBKDF2( +//// password: Array("mypassword".utf8), +//// salt: salt.bytes, +//// iterations: itterations, +//// keyLength: 16, /* 16 == AES-128, 32 == AES-256 */ +//// variant: .sha256 +//// ).calculate() // -// print(privKey) +// // These should be the same +// print("Key 1 -> \(key.asString(base: .base16))") +// //print("Key 2 -> \(key2.asString(base: .base16))") // -// XCTAssertEqual("CM3Nzttt7KmXG9qDEYys++oQ9G749jqrbRRs92BUzpA=", privKey.publicKey.rawRepresentation.asString(base: .base64Pad)) +// //Create our CBC AES Cipher +// let aes = try AES(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: .noPadding) // -// } +// // Try GCM +// //let aes = try AES(key: key.bytes, blockMode: GCM(iv: iv.bytes, mode: .detached), padding: .noPadding) // -// func testED25519PemImport_Private() throws { -// let pem = """ -// -----BEGIN PRIVATE KEY----- -// MC4CAQAwBQYDK2VwBCIEIOkK9EOHRqD5QueUrMZbia55UWpokoFpWco4r2GnRVZ+ -// -----END PRIVATE KEY----- -// """ +// let decryptedKey = try aes.decrypt(ciphertext.bytes) // -// let keyPair = try LibP2PCrypto.Keys.parsePem(pem) +// print(decryptedKey.asString(base: .base64)) // -// print(keyPair) -// XCTAssert(keyPair.keyType == .ed25519) -// XCTAssertNotNil(keyPair.privateKey) -// XCTAssertEqual(keyPair.publicKey.asString(base: .base64Pad), "CM3Nzttt7KmXG9qDEYys++oQ9G749jqrbRRs92BUzpA=") -// } +// let deASN = try Asn1Parser.parse(data: Data(decryptedKey)) +// print(deASN) +// print("-----") +// let unASN = try Asn1Parser.parse(data: pemToData(unencryptedPem)) +// print(unASN) // +// /// sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), // [42,134,72,134,247,13,1,1,1] => RSA Private Key +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 8 bytes), +// /// libp2p_crypto.Asn1Parser.Node.integer(data: 2 bytes) +// /// ]) +// /// ]), +// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ +// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), +// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 16 bytes) +// /// ]) +// /// ]), +// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 640 bytes) +// /// ]) +// /// ]) // -// func testSecp256k1PemImport_Public_Manual() throws { -// let pem = """ -// -----BEGIN PUBLIC KEY----- -// MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzw -// xDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== -// -----END PUBLIC KEY----- -// """ +// var unencRawPrivateKeyData:Data? = nil +// if case .sequence(let top) = unASN { +// if case .octetString(let d) = top.last { +// print("Found our unenc octetString") +// unencRawPrivateKeyData = d +// } +// } +// +// var decRawPrivateKeyData:Data? = nil +// if case .sequence(let top) = deASN { +// if case .octetString(let d) = top.last { +// print("Found our dec octetString") +// decRawPrivateKeyData = d +// } +// } // -// let data = try pemToData(pem) +// guard let uRawPrivKeyData = unencRawPrivateKeyData else { +// return XCTFail("Failed to parse our unencrypted private pem key...") +// } // -// let asn = try Asn1ParserECPrivate.parse(data: data) +// guard let dRawPrivKeyData = decRawPrivateKeyData else { +// return XCTFail("Failed to parse our decrypted private pem key...") +// } // -// print(asn) +// print(uRawPrivKeyData.asString(base: .base64)) +// print(dRawPrivKeyData.asString(base: .base64)) // -//// sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 7 bytes), :id-ecPublicKey -//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 5 bytes) :secp256k1 -//// ]), -//// libp2p_crypto.Asn1Parser.Node.bitString(data: 65 bytes) -//// ]) +// print(dRawPrivKeyData.count) +// print(uRawPrivKeyData.count) // -// guard case .sequence(let top) = asn, case .bitString(let pubKeyData) = top.last else { -// return XCTFail("Failed to extract our Public Key bit/octet string") -// } +// let og = try RSAPrivateKey(rawRepresentation: uRawPrivKeyData) +// let de = try RSAPrivateKey(rawRepresentation: dRawPrivKeyData) // -// let pubKey = try Secp256k1PublicKey(pubKeyData.bytes) +// print(og) // -// print(pubKey) +// print(de) // -// print(pubKey.rawPublicKey.asString(base: .base64Pad)) -// } +// XCTAssertEqual(uRawPrivKeyData, dRawPrivKeyData) +// XCTAssertEqual(og, de) // -// func testSecp256k1PemImport_Public() throws { -// let pem = """ -// -----BEGIN PUBLIC KEY----- -// MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzw -// xDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== -// -----END PUBLIC KEY----- -// """ // -// let keyPair = try LibP2PCrypto.Keys.parsePem(pem) +// //XCTAssertEqual(uRawPrivKeyData.bytes, decryptedKey, "Not Equal") +// } + + func testRSAEncryptedPrivateKeyPem2() throws { + + // Generated with + // openssl genpkey -algorithm RSA + // -pkeyopt rsa_keygen_bits:1024 + // -pkeyopt rsa_keygen_pubexp:65537 + // -out foo.pem + let unencryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.UNENCRYPTED + + // Encrypted with + // openssl pkcs8 -in foo.pem -topk8 -v2 aes-128-cbc -passout pass:mypassword + let encryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.ENCRYPTED + + let fromDecrypted = try LibP2PCrypto.Keys.KeyPair(pem: unencryptedPem) + let fromEncrypted = try LibP2PCrypto.Keys.KeyPair(pem: encryptedPem, password: "mypassword") + + XCTAssertNotNil(fromDecrypted.privateKey) + XCTAssertNotNil(fromEncrypted.privateKey) + + XCTAssertTrue(fromDecrypted.keyType == .rsa) + XCTAssertTrue(fromEncrypted.keyType == .rsa) + + XCTAssertEqual(fromDecrypted.privateKey?.rawRepresentation, fromEncrypted.privateKey?.rawRepresentation) + XCTAssertEqual(fromDecrypted.publicKey.data, fromEncrypted.publicKey.data) + + let attributes = fromEncrypted.attributes() + XCTAssertEqual(attributes!.size, 1024) + XCTAssertTrue(attributes!.isPrivate) + } + + +//// /** +//// * Decrypts the given cipher text with the provided key. The `key` should +//// * be a cryptographically safe key and not a plaintext password. To use +//// * a plaintext password, use `decrypt`. The options used to create +//// * this decryption cipher must be the same as those used to create +//// * the encryption cipher. +//// * +//// * @private +//// * @param {Uint8Array} ciphertextAndNonce The data to decrypt +//// * @param {Uint8Array} key +//// * @returns {Promise} +//// */ +//// async function decryptWithKey (ciphertextAndNonce, key) { // eslint-disable-line require-await +//// // Create Uint8Arrays of nonce, ciphertext and tag. +//// const nonce = ciphertextAndNonce.slice(0, nonceLength) +//// const ciphertext = ciphertextAndNonce.slice(nonceLength, ciphertextAndNonce.length - algorithmTagLength) +//// const tag = ciphertextAndNonce.slice(ciphertext.length + nonceLength) +//// +//// // Create the cipher instance. +//// const cipher = crypto.createDecipheriv(algorithm, key, nonce) +//// +//// // Decrypt and return result. +//// cipher.setAuthTag(tag) +//// return uint8ArrayConcat([cipher.update(ciphertext), cipher.final()]) +//// } +//// +//// /** +//// * Uses the provided password to derive a pbkdf2 key. The key +//// * will then be used to decrypt the data. The options used to create +//// * this decryption cipher must be the same as those used to create +//// * the encryption cipher. +//// * +//// * @param {Uint8Array} data The data to decrypt +//// * @param {string|Uint8Array} password A plain password +//// */ +//// async function decrypt (data, password) { // eslint-disable-line require-await +//// // Create Uint8Arrays of salt and ciphertextAndNonce. +//// const salt = data.slice(0, saltLength) +//// const ciphertextAndNonce = data.slice(saltLength) +//// +//// if (typeof password === 'string' || password instanceof String) { +//// password = uint8ArrayFromString(password) +//// } +//// +//// // Derive the key using PBKDF2. +//// const key = crypto.pbkdf2Sync(password, salt, iterations, keyLength, digest) +//// +//// // Decrypt and return result. +//// return decryptWithKey(ciphertextAndNonce, key) +//// } +//// */ +//// +//// +//// /// Private Key +//// /// Raw Bytes: [1, 187, 116, 255, 157, 152, 71, 218, 87, 128, 62, 200, 148, 52, 164, 109, 237, 133, 89, 216, 240, 207, 80, 244, 60, 41, 32, 117, 184, 2, 231, 7, 9, 237, 110, 180, 86, 120, 103, 133, 84, 215, 104, 137, 101, 171, 127, 154, 54, 153, 229, 201, 46, 20, 1, 221, 211, 59, 129, 102, 129, 5, 76, 249, 30, 182] +//// /// Bytes: 66 +//// /// --- +//// /// Public Key +//// /// Raw Bytes: [0, 110, 196, 197, 185, 248, 73, 76, 67, 3, 127, 38, 67, 168, 163, 6, 20, 223, 146, 233, 198, 22, 77, 105, 120, 172, 14, 6, 95, 144, 206, 161, 48, 16, 46, 29, 26, 53, 177, 60, 132, 212, 146, 37, 203, 104, 104, 81, 129, 246, 149, 222, 98, 0, 249, 7, 134, 50, 83, 122, 75, 74, 242, 216, 234, 152, 0, 196, 255, 251, 57, 249, 20, 79, 95, 72, 156, 153, 174, 189, 153, 145, 253, 72, 69, 57, 114, 180, 179, 100, 173, 183, 100, 235, 84, 42, 66, 116, 93, 139, 64, 190, 225, 15, 90, 159, 178, 212, 204, 25, 174, 159, 36, 177, 45, 227, 230, 147, 191, 167, 141, 103, 47, 96, 183, 159, 143, 89, 155, 144, 199, 38] +//// /// Bytes: 132 +//// /// --- +//// func testECRawRep() throws { +//// let key = P521.Signing.PrivateKey() +//// +//// let rawPrivKey = key.rawRepresentation +//// let rawPubKey = key.publicKey.rawRepresentation +//// +//// //print(key.x963Representation.asString(base: .base64)) +//// print("Private Key") +//// print("Raw Bytes: \(rawPrivKey.bytes)") +//// print("Bytes: \(rawPrivKey.bytes.count)") +//// print("---") +//// //print(rawRep.asString(base: .base64)) +//// print("Public Key") +//// print("Raw Bytes: \(rawPubKey.bytes)") +//// print("Bytes: \(rawPubKey.bytes.count)") +//// print("---") +//// +//// let importedKey = try P521.Signing.PrivateKey(rawRepresentation: rawPrivKey) +//// +//// print(importedKey) +//// } + + func testRSA_Pem_Parsing_Public() throws { + //let parsed = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.RSA_1024_PUBLIC) + let rsaPublic = try RSAPublicKey(pem: TestPEMKeys.RSA_1024_PUBLIC, asType: RSAPublicKey.self) + + print(rsaPublic) + } + + func testRSA_Pem_Parsing_Private() throws { + let rsaPrivate = try RSAPrivateKey(pem: TestPEMKeys.RSA_1024_PRIVATE, asType: RSAPrivateKey.self) + + print(rsaPrivate) + } + +// func testEC_Pem_Parsing_Public() throws { +// let parsed = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.EC_256_PUBLIC) // -// print(keyPair) -// XCTAssert(keyPair.keyType == .secp256k1) -// XCTAssertNil(keyPair.privateKey) -// print(keyPair.attributes() ?? "NIL") +// print(parsed) // } // -// func testSecp256k1PemImport_Private_Manual() throws { -// let pem = """ -// -----BEGIN EC PRIVATE KEY----- -// MHQCAQEEIJmbpwD3mZhlEtiGzmgropJ/nSewc8UPyBE9wib742saoAcGBSuBBAAK -// oUQDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwf -// X7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== -// -----END EC PRIVATE KEY----- -// """ -// -// let data = try pemToData(pem) -// -// let asn = try Asn1ParserECPrivate.parse(data: data) -// -// print(asn) -// -//// sequence(nodes: [ -//// libp2p_crypto.Asn1ParserECPrivate.Node.integer(data: 1 bytes), -//// libp2p_crypto.Asn1ParserECPrivate.Node.octetString(data: 32 bytes), // private key data -//// libp2p_crypto.Asn1ParserECPrivate.Node.objectIdentifier(data: 7 bytes), :secp256k1 -//// libp2p_crypto.Asn1ParserECPrivate.Node.bitString(data: 67 bytes) -//// ]) -// -// guard case .sequence(let top) = asn, case .octetString(let privKeyData) = top[1] else { -// return XCTFail("Failed to extract our PrivKey bit/octet string") -// } -// -// let privKey = try Secp256k1PrivateKey(privKeyData.bytes) -// -// print(privKey) -// -// /// Assert that we can derive the public from the private key -// XCTAssertEqual("IgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w==", privKey.publicKey.rawPublicKey.asString(base: .base64Pad)) +// func testEC_Pem_Parsing_Private() throws { +// let parsed = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.EC_256_PRIVATE) // +// print(parsed) // } -// - func testSecp256k1PemImport_Private() throws { - let pem = """ - -----BEGIN EC PRIVATE KEY----- - MHQCAQEEIJmbpwD3mZhlEtiGzmgropJ/nSewc8UPyBE9wib742saoAcGBSuBBAAK - oUQDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwf - X7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== - -----END EC PRIVATE KEY----- - """ - let keyPair = try LibP2PCrypto.Keys.parsePem(pem) + func testEd25519_Pem_Parsing_Public() throws { + //let parsed = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.Ed25519_KeyPair.PUBLIC) - print(keyPair) - XCTAssert(keyPair.keyType == .secp256k1) - XCTAssertNotNil(keyPair.privateKey) - /// Assert that we can derive the public from the private key - XCTAssertEqual(keyPair.publicKey.asString(base: .base64Pad), "IgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w==") + //print(parsed) + + let ed25519Public = try Curve25519.Signing.PublicKey(pem: TestPEMKeys.Ed25519_KeyPair.PUBLIC, asType: Curve25519.Signing.PublicKey.self) + + print(ed25519Public) + + let ed25519Private = try Curve25519.Signing.PrivateKey(pem: TestPEMKeys.Ed25519_KeyPair.PRIVATE, asType: Curve25519.Signing.PrivateKey.self) + + print(ed25519Private) + + XCTAssertEqual(ed25519Private.publicKey, ed25519Public) } + func testEd25519_Pem_Parsing_Private() throws { + let parsed = try LibP2PCrypto.Keys.KeyPair(pem: TestPEMKeys.Ed25519_KeyPair.PRIVATE) -// func testPemParsing_EC_256_Private_Key() throws { -// let pem = """ -// -----BEGIN EC PRIVATE KEY----- -// MHcCAQEEIHwS3r7tdBfDPSOaT/x6A2qvXFFXlGmnaYkxzrj1CQUHoAoGCCqGSM49 -// AwEHoUQDQgAE79HvsMQC9IyhZ7yCCYKmgz9zewM4KziWoVMXKN+7Cd5Ds+jK8V5q -// hD6YVbbo/v1udmM5DfhHJiUW3Ww5++suRg== -// -----END EC PRIVATE KEY----- -// """ -// -// let chunks = pem.split(separator: "\n") -// guard chunks.count > 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } -// -// let raw = try BaseEncoding.decode(chunks[1.. ec-secp256k1-pub-key.pem` +// func testSecp256k1_Pem_Parsing_Public() throws { +// //let parsed = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.SECP256k1_KeyPair.PUBLIC) // -// var asnOctetString = try LibP2PCrypto.Keys.parseASN1ECPrivate(pemData: raw.data) +// //print(parsed) // -// print(asnOctetString.count) +// //2a8648ce3d0201 +// //2b8104000a +// //let secp256k1Public = try Secp256k1PublicKey(pem: TestPEMKeys.SECP256k1_KeyPair.PUBLIC, asType: Secp256k1PublicKey.self) // -// while asnOctetString.count < 32 { -// asnOctetString.insert(0, at: 0) -// } +// //print(secp256k1Public) // -// let importedKey = try P256.Signing.PrivateKey(rawRepresentation: asnOctetString) +// //let secp256k1Private = try Secp256k1PrivateKey(pem: TestPEMKeys.SECP256k1_KeyPair.PRIVATE, asType: Secp256k1PrivateKey.self) // -// print(importedKey) +// //print(secp256k1Private) // -// print("----") -// } +//// XCTAssertEqual(secp256k1Private.publicKey, secp256k1Public) // -// func testPemParsing_EC_384_Private_Key() throws { -// let pem = """ +// /// 0:d=0 hl=3 l= 162 cons: SEQUENCE +// /// 3:d=1 hl=2 l= 1 prim: INTEGER :01 +// /// 6:d=1 hl=2 l= 44 cons: SEQUENCE +// /// 8:d=2 hl=2 l= 7 prim: OBJECT :prime-field +// /// 17:d=2 hl=2 l= 33 prim: INTEGER :FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F +// /// 52:d=1 hl=2 l= 6 cons: SEQUENCE +// /// 54:d=2 hl=2 l= 1 prim: OCTET STRING [HEX DUMP]:00 +// /// 57:d=2 hl=2 l= 1 prim: OCTET STRING [HEX DUMP]:07 +// /// 60:d=1 hl=2 l= 65 prim: OCTET STRING [HEX DUMP]:0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 +// /// 127:d=1 hl=2 l= 33 prim: INTEGER :FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 +// /// 162:d=1 hl=2 l= 1 prim: INTEGER :01 +// let ecPEM = """ // -----BEGIN EC PRIVATE KEY----- -// MIGkAgEBBDDrN+qjvW7TqcXrKlTFbSP8AdbsIdqvRAgWHlaBicP7dkx+HKQidSiS -// B2RLWyjSrs6gBwYFK4EEACKhZANiAAQrRiaztGpInYo1XqMnNokWY6g1TcgMuzgq -// Ug6LzFQbCAqCrcnM9+c9Z4/63dC06ulL/KbLQgThjSiqRzgbzvmOvB0OzlpX1weK -// usFrF4Pi0B9pKPmVCAlSzaxVEmRsbmw= +// MIIBEwIBAQQgiOURdsStmumMgM2c29TlUxEdNxrQns8VPeM0sV08MtKggaUwgaIC +// AQEwLAYHKoZIzj0BAQIhAP////////////////////////////////////7///wv +// MAYEAQAEAQcEQQR5vmZ++dy7rFWgYpXOhwsHApv82y3OKNlZ8oFbFvgXmEg62ncm +// o8RlXaT7/A4RCKj9F7RIpoVUGZxH0I/7ENS4AiEA/////////////////////rqu +// 3OavSKA7v9JejNA2QUECAQGhRANCAASDsnwEULWLn8HV8iobNGNAdze/SbwbehJ3 +// l+gvkHpYQ2tMD9d4NTMDKFTxPUN+w0ktADgGaPhd2flQ2dNL7nFT // -----END EC PRIVATE KEY----- // """ -// -// let chunks = pem.split(separator: "\n") -// guard chunks.count > 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } -// -// let raw = try BaseEncoding.decode(chunks[1.. 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } -// -// let raw = try BaseEncoding.decode(chunks[1.. 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } +// let parsed = try ASN1.Decoder.decode(data: pemData) // -// let raw = try BaseEncoding.decode(chunks[1.. + /// + /// xsDNBGH7EL8BDADovR5cjh9P26RJ2uNxHuaEmdSFTY6q2uE5s4C6G+JEmtyuqhC9 + /// HEHgl7hv9LbsskLs50J0cCH9KQzMSl2OxztVGR8ABV06oDB+7fhHEPXNA4m1cLmQ + /// zGCp9uDxCs3tuDJRkEMSo97T6AnQwDsl5rBBMqR9c/B7Ozml1aER6ehtxSQt7tuu + /// x/9oD+9zFyUsBOuO20d/Km629h6IHfF+BadbJpzAqHunq+w2P4ks7XYlhFJdhMIq + /// W0h31rI1CO4tM+DG7+6Osz6EJeHWZOc9tWM/5YxmJOA7SZU4t+yedif4bzC4+aCH + /// W2AYlrWKivNOe4n46u1J+xlCtnLyK9Si39ylDuem118diaW1Qs99PkTbWawagYyc + /// c+0flTYeWugLxc2LDUfq9b6r7tfu9hyez0TghdRwlvrQlnZCmEt/Ndg0YF0N3BFE + /// dAzdpsiddEytH28L7hwHE5lECam4mGxBe8uNGYlDu8Viq7IYhyfCM0CNGlEwUQIW + /// I7ahSbKTX66aZxcAEQEAAc0lTG93ZWxsIFRvbXMgPGxvd2VsbHMudmF1bHRAZ21h + /// aWwuY29tPsLBFAQTAQoAPhYhBMRZ5UKAhHyTeb6a7dow5ilh9gp1BQJh+xC/AhsD + /// BQkDwmcABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJENow5ilh9gp1sNoMAItC + /// peoNv5MLrf5XJzP+bi+qmyAkiQSQ+0Jd17G1bUgrmpjeWXUqxu3fWgdxC6+CQLM9 + /// Fj69v11G1nrNlII0vyUN0nxPf9LS5qPMQKXZeAvT+lYrPaNWoE4ShI7MnJhxbME9 + /// TlQNikjOYgWt5dNlO+XqWAqP9ECQ0D2x2ulypVvhYPpvslp0+dQJGfIteTzqHHIY + /// Cu7drWh5Sjy2pvIKOIjjrKapjwqidy6laDi4NDhbu/JWp4im1ZRpIU6qTZgH4b+U + /// kCiAScNbnkYWtlIJ73j+Mh62FzZFQ+lSlVI8Fe/POyCwphVUw9smaEMO1WCsg0zP + /// LLAfnVLhWXdaB1QfchlWU1C/zVtnyCZvkVzDTFCa4IyBrAqUCnXfJHOgivtUU4rl + /// FvgynrDmeKjUqxJsVpEDS524nxR7aVdnfj34879SlJdliHeuwgpYF1q3eQYJMrR/ + /// wDCRBxbGpHTCOVjtU6GEeE9mV93SwVFAFHokD/iJMNTmGiUxFubHQXqCuAKuCc7A + /// zQRh+xC/AQwA0NZs9RjrGAicIFIp6C7NHheyFDL8tet5ZDPO2Lya22AXgnWo3/bs + /// QGXOlxhHJB7TK3Ma5wHAUKJ4BEvxpMtSwHnkFf/EAFZug2AXIvhJpdT8j/Lct6er + /// VusrPxfDmlTH0QeKl3IklnvowyO3r6VeI2Lxga0gWlV+/gRq0vzwXM4vqeXzjNFo + /// cCuNq4jSFT+zztYkud8GbAULBB5oeAp1Dhp+Uk84tu2Lg8rbBhK/H/ax4ozUrWi2 + /// G6azGx9psW9yq+LnQXaCSeGTn8XMqXzuwiD87TZgvuih/8iyMDoaFnuSKCw4v1WQ + /// 8wWusZ2e0a05SCiRpYDlv+CJ93J5F1ApZXjD9NpYcU0O53zl+wqqNbj1HtxoGPrT + /// EHvKPYZru/Dtea+sAxEXpYpUXFamQq4zIaI+dagD3vzSmFLRuCtaZElHhsS3t91K + /// tQBKon1ZEN/VwdO7tix6gfDMMa3BpnllI2eaw2X+Ucdkm/jJHuPoxfy1lbFP8byy + /// fDXvhR8Pnk8TABEBAAHCwPwEGAEKACYWIQTEWeVCgIR8k3m+mu3aMOYpYfYKdQUC + /// YfsQvwIbDAUJA8JnAAAKCRDaMOYpYfYKddh5DADGLKm9AmtCh7bUR+r+MKdCyjTO + /// LSiu0WACRUHIw+RLu5J5/haa7xZKPo6iN955oUS3j9CK0NTr/+ZxdDFwVc7kAjOn + /// eoZefac0CFRtLO26LQcVh5jc6YV0ZVtchvbnWCOfwtsvVfsQUCo7oIfP2CacEGq2 + /// EIqYLTJ7leVgo3AqlR5MmPA+umMKVcb/KDkesMnhgThw3F+81cocRhxWVlNQam0/ + /// PAj2uprXt+yWU8K94gojmolBuSdBBMZGArjBr/oCAhBrWarg4gEnC0tGQBBLU1Us + /// YEdv+2OYokrlIU96P2mtCDX+9GId+idUlgEPc+CQr3Um9W/syyxGI2e2wSlAlkjh + /// +h84GvLvZpM9HU4HrHF5AxmXoEe2BF7ICHHju0vdignpEdtQ/XHckSLlxcJz8i2S + /// XkMi7m1i5U0OWEXVr+Z3jeW2HVVEvEJ7aXL3oLLAVz3TROFY0M41zjrstyjg0sg5 + /// 5H93wgN5hgZ8MeDFEWbEh3p7e/MP9I/lo70bkA0= + /// =n56n + /// -----END PGP PUBLIC KEY BLOCK----- +// func testOpen_ASC_PGP_PublicKey() throws { +// let urls = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask) +// let downloadsFolder = urls[0] // -// // Raw Representation of our key -// print(unencryptedKey.asString(base: .base16)) +// print(downloadsFolder) +// let fileURL = downloadsFolder.appendingPathComponent("C459E54280847C9379BE9AEDDA30E62961F60A75.asc") // -// //Import Unencrypted Key as SecKey... +// let pubKey = try String(contentsOf: fileURL, encoding: .utf8) // -//// /* Encrypt Data */ -//// let inputData = Data() -//// let encryptedBytes = try aes.encrypt(inputData.bytes) -//// let encryptedData = Data(encryptedBytes) -//// -//// /* Decrypt Data */ -//// let decryptedBytes = try aes.decrypt(encryptedData.bytes) -//// let decryptedData = Data(decryptedBytes) +// print(pubKey) // +// //let keyPair = try LibP2PCrypto.Keys.parsePem(pubKey) +// let keyPair = try LibP2PCrypto.Keys.importPublicPem(pubKey) // +// print(keyPair) // } - // - MARK: Encrypted PEM Imports +// func testOpen_PGP_PublicKey() throws { +// +// let pubKey = """ +// xsDNBGH7EL8BDADovR5cjh9P26RJ2uNxHuaEmdSFTY6q2uE5s4C6G+JEmtyuqhC9 +// HEHgl7hv9LbsskLs50J0cCH9KQzMSl2OxztVGR8ABV06oDB+7fhHEPXNA4m1cLmQ +// zGCp9uDxCs3tuDJRkEMSo97T6AnQwDsl5rBBMqR9c/B7Ozml1aER6ehtxSQt7tuu +// x/9oD+9zFyUsBOuO20d/Km629h6IHfF+BadbJpzAqHunq+w2P4ks7XYlhFJdhMIq +// W0h31rI1CO4tM+DG7+6Osz6EJeHWZOc9tWM/5YxmJOA7SZU4t+yedif4bzC4+aCH +// W2AYlrWKivNOe4n46u1J+xlCtnLyK9Si39ylDuem118diaW1Qs99PkTbWawagYyc +// c+0flTYeWugLxc2LDUfq9b6r7tfu9hyez0TghdRwlvrQlnZCmEt/Ndg0YF0N3BFE +// dAzdpsiddEytH28L7hwHE5lECam4mGxBe8uNGYlDu8Viq7IYhyfCM0CNGlEwUQIW +// I7ahSbKTX66aZxcAEQEAAc0lTG93ZWxsIFRvbXMgPGxvd2VsbHMudmF1bHRAZ21h +// aWwuY29tPsLBFAQTAQoAPhYhBMRZ5UKAhHyTeb6a7dow5ilh9gp1BQJh+xC/AhsD +// BQkDwmcABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJENow5ilh9gp1sNoMAItC +// peoNv5MLrf5XJzP+bi+qmyAkiQSQ+0Jd17G1bUgrmpjeWXUqxu3fWgdxC6+CQLM9 +// Fj69v11G1nrNlII0vyUN0nxPf9LS5qPMQKXZeAvT+lYrPaNWoE4ShI7MnJhxbME9 +// TlQNikjOYgWt5dNlO+XqWAqP9ECQ0D2x2ulypVvhYPpvslp0+dQJGfIteTzqHHIY +// Cu7drWh5Sjy2pvIKOIjjrKapjwqidy6laDi4NDhbu/JWp4im1ZRpIU6qTZgH4b+U +// kCiAScNbnkYWtlIJ73j+Mh62FzZFQ+lSlVI8Fe/POyCwphVUw9smaEMO1WCsg0zP +// LLAfnVLhWXdaB1QfchlWU1C/zVtnyCZvkVzDTFCa4IyBrAqUCnXfJHOgivtUU4rl +// FvgynrDmeKjUqxJsVpEDS524nxR7aVdnfj34879SlJdliHeuwgpYF1q3eQYJMrR/ +// wDCRBxbGpHTCOVjtU6GEeE9mV93SwVFAFHokD/iJMNTmGiUxFubHQXqCuAKuCc7A +// zQRh+xC/AQwA0NZs9RjrGAicIFIp6C7NHheyFDL8tet5ZDPO2Lya22AXgnWo3/bs +// QGXOlxhHJB7TK3Ma5wHAUKJ4BEvxpMtSwHnkFf/EAFZug2AXIvhJpdT8j/Lct6er +// VusrPxfDmlTH0QeKl3IklnvowyO3r6VeI2Lxga0gWlV+/gRq0vzwXM4vqeXzjNFo +// cCuNq4jSFT+zztYkud8GbAULBB5oeAp1Dhp+Uk84tu2Lg8rbBhK/H/ax4ozUrWi2 +// G6azGx9psW9yq+LnQXaCSeGTn8XMqXzuwiD87TZgvuih/8iyMDoaFnuSKCw4v1WQ +// 8wWusZ2e0a05SCiRpYDlv+CJ93J5F1ApZXjD9NpYcU0O53zl+wqqNbj1HtxoGPrT +// EHvKPYZru/Dtea+sAxEXpYpUXFamQq4zIaI+dagD3vzSmFLRuCtaZElHhsS3t91K +// tQBKon1ZEN/VwdO7tix6gfDMMa3BpnllI2eaw2X+Ucdkm/jJHuPoxfy1lbFP8byy +// fDXvhR8Pnk8TABEBAAHCwPwEGAEKACYWIQTEWeVCgIR8k3m+mu3aMOYpYfYKdQUC +// YfsQvwIbDAUJA8JnAAAKCRDaMOYpYfYKddh5DADGLKm9AmtCh7bUR+r+MKdCyjTO +// LSiu0WACRUHIw+RLu5J5/haa7xZKPo6iN955oUS3j9CK0NTr/+ZxdDFwVc7kAjOn +// eoZefac0CFRtLO26LQcVh5jc6YV0ZVtchvbnWCOfwtsvVfsQUCo7oIfP2CacEGq2 +// EIqYLTJ7leVgo3AqlR5MmPA+umMKVcb/KDkesMnhgThw3F+81cocRhxWVlNQam0/ +// PAj2uprXt+yWU8K94gojmolBuSdBBMZGArjBr/oCAhBrWarg4gEnC0tGQBBLU1Us +// YEdv+2OYokrlIU96P2mtCDX+9GId+idUlgEPc+CQr3Um9W/syyxGI2e2wSlAlkjh +// +h84GvLvZpM9HU4HrHF5AxmXoEe2BF7ICHHju0vdignpEdtQ/XHckSLlxcJz8i2S +// XkMi7m1i5U0OWEXVr+Z3jeW2HVVEvEJ7aXL3oLLAVz3TROFY0M41zjrstyjg0sg5 +// 5H93wgN5hgZ8MeDFEWbEh3p7e/MP9I/lo70bkA0= +// =n56n +// """ +// +// let data = try BaseEncoding.decode(pubKey, as: .base64) +// print(data) +// +// //let keyPair = try LibP2PCrypto.Keys.parsePem(pubKey) +// //let keyPair = try LibP2PCrypto.Keys.importPublicPem(pubKey) +// //let keyPair = try LibP2PCrypto.Keys.importPublicDER(pubKey) +// //let keyPair = try LibP2PCrypto.Keys. +// +// //print(keyPair) +// } - /// Tests importing encrypted PEM private key with a plaintext password + /// Is the public key embedded in these IDs?? + /// Dialed: 12D3KooWAfPDpPRRRBrmqy9is2zjU5srQ4hKuZitiGmh4NTTpS2d + /// Provided: QmPoHmYtUt8BU9eiwMYdBfT6rooBnna5fdAZHUaZASGQY8 + /// QmPoHmYtUt8BU9eiwMYdBfT6rooBnna5fdAZHUaZASGQY8 /// - /// To decrypt an encrypted private RSA key... - /// 1) Strip the headers of the PEM and base64 decode the data - /// 2) Parse the data via ASN1 looking for the encryption algo, salt, iv and itterations used, and the ciphertext (aka octet string) - /// 3) Derive the encryption key using PBKDF2 (sha1, salt and itterations) - /// 4) Use encryption key to instantiate the AES CBC Cipher along with the IV - /// 5) Decrypt the encrypted octet string - /// 6) The decrypted octet string can be ASN1 parsed again for the private key octet string - /// 7) This raw data can be used to instantiate a SecKey -// func testRSAEncryptedPrivateKeyPem2_Manual() throws { -// -// // Generated with -// // openssl genpkey -algorithm RSA -// // -pkeyopt rsa_keygen_bits:1024 -// // -pkeyopt rsa_keygen_pubexp:65537 -// // -out foo.pem -// let unencryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.UNENCRYPTED -// -// // Encrypted with -// // openssl pkcs8 -in foo.pem -topk8 -v2 aes-128-cbc -passout pass:mypassword -// let encryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.ENCRYPTED -// -// let asn = try Asn1Parser.parse(data: pemToData(encryptedPem)) -// -// print(asn) -// -//// sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //[42,134,72,134,247,13,1,5,13] -//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //PBKDF2 //[42,134,72,134,247,13,1,5,12] -//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.octetString(data: 8 bytes), //SALT -//// libp2p_crypto.Asn1Parser.Node.integer(data: 2 bytes) //ITTERATIONS -//// ]) -//// ]), -//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //des-ede3-cbc [96,134,72,1,101,3,4,1,2] -//// libp2p_crypto.Asn1Parser.Node.octetString(data: 16 bytes) //IV -//// ]) -//// ]) -//// ]), -//// libp2p_crypto.Asn1Parser.Node.octetString(data: 640 bytes) -//// ]) -// -// var saltData:Data? = nil -// var ivData:Data? = nil -// var itterationsData:Int? = nil -// var ciphertextData:Data? = nil -// -// if case .sequence(let top) = asn { -// if case .sequence(let top1) = top.first { -// if case .sequence(let top2) = top1.last { -// if case .sequence(let top3) = top2.first { -// if case .sequence(let top4) = top3.last { -// if case .octetString(let salt) = top4.first { -// print("Found the salt: \(salt.asString(base: .base16))") -// saltData = salt -// } -// if case .integer(let int) = top4.last { -// print("Found the itterations: \(int.asString(base: .base16))") -// itterationsData = Int(int.asString(base: .base16), radix: 16) -// } -// } -// } -// if case .sequence(let bottom3) = top2.last { -// if case .octetString(let iv) = bottom3.last { -// print("Found the IV: \(iv.asString(base: .base16))") -// ivData = iv -// } -// } -// } -// } -// if case .octetString(let cipherText) = top.last { -// print("Found the ciphertext: \(cipherText.count)") -// ciphertextData = cipherText -// } -// } -// -// // Ensure we have everything we need to proceed... -// guard let salt = saltData, let iv = ivData, let itterations = itterationsData, let ciphertext = ciphertextData else { -// return XCTFail("Failed to parse our pcks#8 key") -// } -// -// // Attempt to derive the aes encryption key from the password and salt -// // PBKDF2-SHA1 -// guard let key = PBKDF2.SHA1(password: "mypassword", salt: salt, keyByteCount: 16, rounds: itterations) else { -// return XCTFail("Failed to derive key from password and salt") -// } -// -// // This also works, but it is incredibly slow... -//// let key2 = try PKCS5.PBKDF2( -//// password: Array("mypassword".utf8), -//// salt: salt.bytes, -//// iterations: itterations, -//// keyLength: 16, /* 16 == AES-128, 32 == AES-256 */ -//// variant: .sha256 -//// ).calculate() + /// Dialed: 12D3KooWF5Qbrbvhhha1AcqRULWAfYzFEnKvWVGBUjw489hpo5La + /// Provided: Qmbp3SxL2SYcH6Ly4r5SGQwfxkDCJPuhJG35GCZimcTiBc + /// Qmbp3SxL2SYcH6Ly4r5SGQwfxkDCJPuhJG35GCZimcTiBc + func testEmbeddedEd25519PublicKey() throws { + + let multi = try Multihash(b58String: "12D3KooWF5Qbrbvhhha1AcqRULWAfYzFEnKvWVGBUjw489hpo5La") + print(multi) + print("\(multi.value) (\(multi.value.count))") + print("\(multi.digest!) (\(multi.digest!.count))") + + let key = try Curve25519.Signing.PublicKey(rawRepresentation: multi.digest!.dropFirst(4)) + print(key) + + let kp = try LibP2PCrypto.Keys.KeyPair(publicKey: key) + + print(kp) + + print(try kp.id(withMultibasePrefix: false)) + + let marshed = try LibP2PCrypto.Keys.KeyPair(marshaledPublicKey: Data(multi.digest!)) + print(marshed) + + print(marshed.keyType) + print(marshed.publicKey) + print(try marshed.id(withMultibasePrefix: false)) + + } + + static var allTests = [ + ("testRSA1024", testRSA1024), + ("tesED25519", testED25519), + ("testSecp256k1", testSecp256k1), + ("testRSARawRepresentationRoundTrip", testRSARawRepresentationRoundTrip), + ("testEd25519RawRepresentationRoundTrip", testEd25519RawRepresentationRoundTrip), + ("testSecP256k1RawRepresentationRoundTrip", testSecP256k1RawRepresentationRoundTrip), + ("testRSAMarshaledRoundTrip", testRSAMarshaledRoundTrip), + ("testRSAMashallingRoundTrip", testRSAMashallingRoundTrip), + ("testED25519MarshallingRoundTrip", testED25519MarshallingRoundTrip), + ("testSecp256k1MarshallingRoundTrip", testSecp256k1MarshallingRoundTrip), + ("testImportFromMarshalledPublicKey_Manual", testImportFromMarshalledPublicKey_Manual), + ("testCreateKeyPairFromMarshalledPublicKey_1024", testCreateKeyPairFromMarshalledPublicKey_1024), + ("testCreateKeyPairFromMarshalledPublicKey_2048", testCreateKeyPairFromMarshalledPublicKey_2048), + ("testCreateKeyPairFromMarshalledPublicKey_3072", testCreateKeyPairFromMarshalledPublicKey_3072), + ("testCreateKeyPairFromMarshalledPublicKey_4096", testCreateKeyPairFromMarshalledPublicKey_4096), + ("testImportFromMarshalledPrivateKey_Manual", testImportFromMarshalledPrivateKey_Manual), + ("testImportFromMarshalledPrivateKey_1024", testImportFromMarshalledPrivateKey_1024), + ("testImportFromMarshalledPrivateKey_2048", testImportFromMarshalledPrivateKey_2048), + ("testImportFromMarshalledPrivateKey_3072", testImportFromMarshalledPrivateKey_3072), + ("testImportFromMarshalledPrivateKey_4096", testImportFromMarshalledPrivateKey_4096), + ("testRSAMessageSignVerify_StaticKey", testRSAMessageSignVerify_StaticKey), + ("testRSAMessageSignVerify_DynamicKey", testRSAMessageSignVerify_DynamicKey), + ("testED25519MessageSignVerify", testED25519MessageSignVerify), + ("testSecp256k1MessageSignVerify", testSecp256k1MessageSignVerify), + ("testAESEncryption128", testAESEncryption128), + ("testAESEncryption256", testAESEncryption256), + ("testAESEncryption256AutoIV", testAESEncryption256AutoIV), + ("testAESEncryption256AutoIVDifferent", testAESEncryption256AutoIVDifferent), + ("testAESGCMEncryptionRoundTrip", testAESGCMEncryptionRoundTrip), + ("testHMAC", testHMAC), + ("testHMACKey", testHMACKey), + ("testHMACBaseEncoded", testHMACBaseEncoded), + ("testHMACVerify", testHMACVerify), + //("testPemParsing", testPemParsing), + ("testPemParsing_RSA_1024_Public", testPemParsing_RSA_1024_Public), + ("testPemParsing_RSA_1024_Public_2", testPemParsing_RSA_1024_Public_2), + ("testPemParsing_RSA_2048_Public", testPemParsing_RSA_2048_Public), + ("testPemParsing_RSA_3072_Public", testPemParsing_RSA_3072_Public), + ("testPemParsing_RSA_4096_Public", testPemParsing_RSA_4096_Public), + ("testRSAOpenSSLPemImport", testRSAOpenSSLPemImport), + ("testED25519PemImport_Public_Manual", testED25519PemImport_Public_Manual), + ("testED25519PemImport_Public", testED25519PemImport_Public), + ("testED25519PemImport_Private_Manual", testED25519PemImport_Private_Manual), + ("testED25519PemImport_Private", testED25519PemImport_Private), + ("testSecp256k1PemImport_Public_Manual", testSecp256k1PemImport_Public_Manual), + ("testSecp256k1PemImport_Public", testSecp256k1PemImport_Public), + ("testSecp256k1PemImport_Private_Manual", testSecp256k1PemImport_Private_Manual), + ("testSecp256k1PemImport_Private", testSecp256k1PemImport_Private), + //("testRSAEncryptedPrivateKeyPem2_Manual", testRSAEncryptedPrivateKeyPem2_Manual), + ("testRSAEncryptedPrivateKeyPem2", testRSAEncryptedPrivateKeyPem2), + ("testRSA_Pem_Parsing_Public", testRSA_Pem_Parsing_Public), + ("testRSA_Pem_Parsing_Private", testRSA_Pem_Parsing_Private), + ("testEd25519_Pem_Parsing_Public", testEd25519_Pem_Parsing_Public), + //("testEd25519_Pem_Parsing_Private", testEd25519_Pem_Parsing_Private), + //("testSecp256k1_Pem_Parsing_Public", testSecp256k1_Pem_Parsing_Public), + ("testSecp256k1_Pem_Parsing_Private", testSecp256k1_Pem_Parsing_Private), + ("testEmbeddedEd25519PublicKey", testEmbeddedEd25519PublicKey) + ] +} + + +// /// Eliptic Curves +// func testEC256() throws { +// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.EC(curve: .P256)) +// print(keyPair) +// } // -// // These should be the same -// print("Key 1 -> \(key.asString(base: .base16))") -// //print("Key 2 -> \(key2.asString(base: .base16))") +// func testEC256KeyPair() throws { +// let keyPair = try LibP2PCrypto.Keys.generateKeyPair(.EC(curve: .P256)) +// XCTAssertFalse(keyPair.publicKey.isRSAKey) +// XCTAssertTrue(keyPair.publicKey.isPublicKey) +// XCTAssertFalse(keyPair.privateKey.isPublicKey) +// } // -// //Create our CBC AES Cipher -// let aes = try AES(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: .noPadding) +// func testECDSA256() throws { +// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.ECDSA(curve: .P256)) +// print(keyPair) +// } // -// // Try GCM -// //let aes = try AES(key: key.bytes, blockMode: GCM(iv: iv.bytes, mode: .detached), padding: .noPadding) +// func testECDSA384() throws { +// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.ECDSA(curve: .P384)) +// print(keyPair) +// } // -// let decryptedKey = try aes.decrypt(ciphertext.bytes) +// func testECDSA521() throws { +// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.ECDSA(curve: .P521)) +// print(keyPair) +// } // -// print(decryptedKey.asString(base: .base64)) +// func testECSecPrimeRandom() throws { +// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.ECSECPrimeRandom()) +// print(keyPair) +// } + +// func testEphemeralMashallingRoundTrip() throws { +// let keyPair = try LibP2PCrypto.Keys.generateRawEphemeralKeyPair(curve: .P256) // -// let deASN = try Asn1Parser.parse(data: Data(decryptedKey)) -// print(deASN) -// print("-----") -// let unASN = try Asn1Parser.parse(data: pemToData(unencryptedPem)) -// print(unASN) +// print("Public Key: \(keyPair.publicKey.asString(base: .base16))") // -// /// sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), // [42,134,72,134,247,13,1,1,1] => RSA Private Key -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 8 bytes), -// /// libp2p_crypto.Asn1Parser.Node.integer(data: 2 bytes) -// /// ]) -// /// ]), -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), -// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 16 bytes) -// /// ]) -// /// ]), -// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 640 bytes) -// /// ]) -// /// ]) +// let marshaledPubKey = try LibP2PCrypto.Keys.marshalPublicKey(raw: keyPair.publicKey, keyType: .ECDSA(curve: .P256)) +// print("Marshaled PubKey Bytes: \(marshaledPubKey)") // -// var unencRawPrivateKeyData:Data? = nil -// if case .sequence(let top) = unASN { -// if case .octetString(let d) = top.last { -// print("Found our unenc octetString") -// unencRawPrivateKeyData = d -// } -// } +// let unmarshaledPubKey = try LibP2PCrypto.Keys.unmarshalPublicKey(buf: marshaledPubKey, into: .base16) // -// var decRawPrivateKeyData:Data? = nil -// if case .sequence(let top) = deASN { -// if case .octetString(let d) = top.last { -// print("Found our dec octetString") -// decRawPrivateKeyData = d -// } -// } +// print("Public Key: \(unmarshaledPubKey)") +// XCTAssertEqual(unmarshaledPubKey, keyPair.publicKey.asString(base: .base16)) +// } // -// guard let uRawPrivKeyData = unencRawPrivateKeyData else { -// return XCTFail("Failed to parse our unencrypted private pem key...") -// } + +// func testPemParsing_EC_256_Private_Key() throws { +// let pem = """ +// -----BEGIN EC PRIVATE KEY----- +// MHcCAQEEIHwS3r7tdBfDPSOaT/x6A2qvXFFXlGmnaYkxzrj1CQUHoAoGCCqGSM49 +// AwEHoUQDQgAE79HvsMQC9IyhZ7yCCYKmgz9zewM4KziWoVMXKN+7Cd5Ds+jK8V5q +// hD6YVbbo/v1udmM5DfhHJiUW3Ww5++suRg== +// -----END EC PRIVATE KEY----- +// """ // -// guard let dRawPrivKeyData = decRawPrivateKeyData else { -// return XCTFail("Failed to parse our decrypted private pem key...") +// let chunks = pem.split(separator: "\n") +// guard chunks.count > 3, +// let f = chunks.first, f.hasPrefix("-----BEGIN"), +// let l = chunks.last, l.hasSuffix("-----") else { +// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) // } // -// print(uRawPrivKeyData.asString(base: .base64)) -// print(dRawPrivKeyData.asString(base: .base64)) -// -// print(dRawPrivKeyData.count) -// print(uRawPrivKeyData.count) +// let raw = try BaseEncoding.decode(chunks[1.. Data { -// let chunks = str.split(separator: "\n") -// guard chunks.count > 2, +// let chunks = pem.split(separator: "\n") +// guard chunks.count > 3, // let f = chunks.first, f.hasPrefix("-----BEGIN"), // let l = chunks.last, l.hasSuffix("-----") else { // throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) // } // -// return try BaseEncoding.decode(chunks[1..} The private key protobuf -//// */ -//// import: async function (privateKey, password) { -//// const base64 = multibase.names.base64 -//// const encryptedKey = base64.decode(privateKey) -//// const cipher = ciphers.create() -//// return await cipher.decrypt(encryptedKey, password) -//// } -//// -//// function create ({ -//// algorithmTagLength = 16, -//// nonceLength = 12, -//// keyLength = 16, -//// digest = 'sha256', -//// saltLength = 16, -//// iterations = 32767 -//// } = {}) { -//// const algorithm = 'aes-128-gcm' -//// -//// /** -//// * Decrypts the given cipher text with the provided key. The `key` should -//// * be a cryptographically safe key and not a plaintext password. To use -//// * a plaintext password, use `decrypt`. The options used to create -//// * this decryption cipher must be the same as those used to create -//// * the encryption cipher. -//// * -//// * @private -//// * @param {Uint8Array} ciphertextAndNonce The data to decrypt -//// * @param {Uint8Array} key -//// * @returns {Promise} -//// */ -//// async function decryptWithKey (ciphertextAndNonce, key) { // eslint-disable-line require-await -//// // Create Uint8Arrays of nonce, ciphertext and tag. -//// const nonce = ciphertextAndNonce.slice(0, nonceLength) -//// const ciphertext = ciphertextAndNonce.slice(nonceLength, ciphertextAndNonce.length - algorithmTagLength) -//// const tag = ciphertextAndNonce.slice(ciphertext.length + nonceLength) -//// -//// // Create the cipher instance. -//// const cipher = crypto.createDecipheriv(algorithm, key, nonce) -//// -//// // Decrypt and return result. -//// cipher.setAuthTag(tag) -//// return uint8ArrayConcat([cipher.update(ciphertext), cipher.final()]) -//// } -//// -//// /** -//// * Uses the provided password to derive a pbkdf2 key. The key -//// * will then be used to decrypt the data. The options used to create -//// * this decryption cipher must be the same as those used to create -//// * the encryption cipher. -//// * -//// * @param {Uint8Array} data The data to decrypt -//// * @param {string|Uint8Array} password A plain password -//// */ -//// async function decrypt (data, password) { // eslint-disable-line require-await -//// // Create Uint8Arrays of salt and ciphertextAndNonce. -//// const salt = data.slice(0, saltLength) -//// const ciphertextAndNonce = data.slice(saltLength) -//// -//// if (typeof password === 'string' || password instanceof String) { -//// password = uint8ArrayFromString(password) -//// } -//// -//// // Derive the key using PBKDF2. -//// const key = crypto.pbkdf2Sync(password, salt, iterations, keyLength, digest) -//// -//// // Decrypt and return result. -//// return decryptWithKey(ciphertextAndNonce, key) -//// } -//// */ -//// -//// -//// /// Private Key -//// /// Raw Bytes: [1, 187, 116, 255, 157, 152, 71, 218, 87, 128, 62, 200, 148, 52, 164, 109, 237, 133, 89, 216, 240, 207, 80, 244, 60, 41, 32, 117, 184, 2, 231, 7, 9, 237, 110, 180, 86, 120, 103, 133, 84, 215, 104, 137, 101, 171, 127, 154, 54, 153, 229, 201, 46, 20, 1, 221, 211, 59, 129, 102, 129, 5, 76, 249, 30, 182] -//// /// Bytes: 66 -//// /// --- -//// /// Public Key -//// /// Raw Bytes: [0, 110, 196, 197, 185, 248, 73, 76, 67, 3, 127, 38, 67, 168, 163, 6, 20, 223, 146, 233, 198, 22, 77, 105, 120, 172, 14, 6, 95, 144, 206, 161, 48, 16, 46, 29, 26, 53, 177, 60, 132, 212, 146, 37, 203, 104, 104, 81, 129, 246, 149, 222, 98, 0, 249, 7, 134, 50, 83, 122, 75, 74, 242, 216, 234, 152, 0, 196, 255, 251, 57, 249, 20, 79, 95, 72, 156, 153, 174, 189, 153, 145, 253, 72, 69, 57, 114, 180, 179, 100, 173, 183, 100, 235, 84, 42, 66, 116, 93, 139, 64, 190, 225, 15, 90, 159, 178, 212, 204, 25, 174, 159, 36, 177, 45, 227, 230, 147, 191, 167, 141, 103, 47, 96, 183, 159, 143, 89, 155, 144, 199, 38] -//// /// Bytes: 132 -//// /// --- -//// func testECRawRep() throws { -//// let key = P521.Signing.PrivateKey() -//// -//// let rawPrivKey = key.rawRepresentation -//// let rawPubKey = key.publicKey.rawRepresentation -//// -//// //print(key.x963Representation.asString(base: .base64)) -//// print("Private Key") -//// print("Raw Bytes: \(rawPrivKey.bytes)") -//// print("Bytes: \(rawPrivKey.bytes.count)") -//// print("---") -//// //print(rawRep.asString(base: .base64)) -//// print("Public Key") -//// print("Raw Bytes: \(rawPubKey.bytes)") -//// print("Bytes: \(rawPubKey.bytes.count)") -//// print("---") -//// -//// let importedKey = try P521.Signing.PrivateKey(rawRepresentation: rawPrivKey) -//// -//// print(importedKey) -//// } -//// -//// func testImportEncryptedPemKey() throws { -//// /* -//// * Generated with -//// * openssl genpkey -algorithm RSA -//// * -pkeyopt rsa_keygen_bits:1024 -//// * -pkeyopt rsa_keygen_pubexp:65537 -//// * -out foo.pem -//// * openssl pkcs8 -in foo.pem -topk8 -v2 des3 -passout pass:mypassword -//// */ -//// let pem = """ -//// -----BEGIN ENCRYPTED PRIVATE KEY----- -//// MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQISznrfHd+D58CAggA -//// MBQGCCqGSIb3DQMHBAhx0DnnUvDiHASCAoCceplm+Cmwlgvn4hNsv6e4c/S1iA7w -//// 2hU7Jt8JgRCIMWjP2FthXOAFLa2fD4g3qncYXcDAFBXNyoh25OgOwstO14YkxhDi -//// wG4TeppGUt9IlyyCol6Z4WhQs1TGm5OcD5xDta+zBXsBnlgmKLD5ZXPEYB+3v/Dg -//// SvM4sQz6NgkVHN52hchERsnknwSOghiK9mIBH0RZU5LgzlDy2VoBCiEPVdZ7m4F2 -//// dft5e82zFS58vwDeNN/0r7fC54TyJf/8k3q94+4Hp0mseZ67LR39cvnEKuDuFROm -//// kLPLekWt5R2NGdunSQlA79BkrNB1ADruO8hQOOHMO9Y3/gNPWLKk+qrfHcUni+w3 -//// Ofq+rdfakHRb8D6PUmsp3wQj6fSOwOyq3S50VwP4P02gKcZ1om1RvEzTbVMyL3sh -//// hZcVB3vViu3DO2/56wo29lPVTpj9bSYjw/CO5jNpPBab0B/Gv7JAR0z4Q8gn6OPy -//// qf+ddyW4Kcb6QUtMrYepghDthOiS3YJV/zCNdL3gTtVs5Ku9QwQ8FeM0/5oJZPlC -//// TxGuOFEJnYRWqIdByCP8mp/qXS5alSR4uoYQSd7vZG4vkhkPNSAwux/qK1IWfqiW -//// 3XlZzrbD//9IzFVqGRs4nRIFq85ULK0zAR57HEKIwGyn2brEJzrxpV6xsHBp+m4w -//// 6r0+PtwuWA0NauTCUzJ1biUdH8t0TgBL6YLaMjlrfU7JstH3TpcZzhJzsjfy0+zV -//// NT2TO3kSzXpQ5M2VjOoHPm2fqxD/js+ThDB3QLi4+C7HqakfiTY1lYzXl9/vayt6 -//// DUD29r9pYL9ErB9tYko2rat54EY7k7Ts6S5jf+8G7Zz234We1APhvqaG -//// -----END ENCRYPTED PRIVATE KEY----- -//// """ -//// -//// let chunks = pem.split(separator: "\n") -//// guard chunks.count > 3, -//// let f = chunks.first, f.hasPrefix("-----BEGIN"), -//// let l = chunks.last, l.hasSuffix("-----") else { -//// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -//// } -//// -//// let raw = try BaseEncoding.decode(chunks[1.. 3, +// let f = chunks.first, f.hasPrefix("-----BEGIN"), +// let l = chunks.last, l.hasSuffix("-----") else { +// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) +// } +// +// let raw = try BaseEncoding.decode(chunks[1.. ec-secp256k1-pub-key.pem` - func testSecp256k1_Pem_Parsing_Public() throws { - //let parsed = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.SECP256k1_KeyPair.PUBLIC) - - //print(parsed) - - //2a8648ce3d0201 - //2b8104000a - //let secp256k1Public = try Secp256k1PublicKey(pem: TestPEMKeys.SECP256k1_KeyPair.PUBLIC, asType: Secp256k1PublicKey.self) - - //print(secp256k1Public) - - //let secp256k1Private = try Secp256k1PrivateKey(pem: TestPEMKeys.SECP256k1_KeyPair.PRIVATE, asType: Secp256k1PrivateKey.self) - - //print(secp256k1Private) +// func testPemParsing_EC_P384_Public() throws { +// /// EC P384 Public Key +// let pem = """ +// -----BEGIN PUBLIC KEY----- +// MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEBwY0l7mq7hSBEZRld5ISWfSoFsYN3wwM +// hdD3cMU95DmYXzbqVHB4dCfsy7bexm4h9c0zs4CyTPzy3DV3vfmv1akQJIQv7l08 +// lx/YXNeGXTN4Gr9r4rwA5GvRl1p6plPL +// -----END PUBLIC KEY----- +// """ +// +// let key = try LibP2PCrypto.Keys.importPublicPem(pem) +// +// print(key) +// } +// +// func testPemParsing_EC_P521_Public() throws { +// /// EC P521 Public Key +// let pem = """ +// -----BEGIN PUBLIC KEY----- +// MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAp3v1UQWvSyQnkAUEBu+x/7ZrPtNJ +// SCUk9kMvuZMyGP1idwvspALuJjzrSFFlXObjlOjxucSbWhTYF/o3nc0XzpAA3dxA +// BYiMqH9vrVePoJMpv+DMdkUiUJ/WqHSOu9bJEi1h4fdqh5HHx4QZJY/iX/59VAi1 +// uSbAhALvbdGFbVpkcOs= +// -----END PUBLIC KEY----- +// """ +// +// let key = try LibP2PCrypto.Keys.importPublicPem(pem) +// +// print(key) +// } -// XCTAssertEqual(secp256k1Private.publicKey, secp256k1Public) - - /// 0:d=0 hl=3 l= 162 cons: SEQUENCE - /// 3:d=1 hl=2 l= 1 prim: INTEGER :01 - /// 6:d=1 hl=2 l= 44 cons: SEQUENCE - /// 8:d=2 hl=2 l= 7 prim: OBJECT :prime-field - /// 17:d=2 hl=2 l= 33 prim: INTEGER :FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F - /// 52:d=1 hl=2 l= 6 cons: SEQUENCE - /// 54:d=2 hl=2 l= 1 prim: OCTET STRING [HEX DUMP]:00 - /// 57:d=2 hl=2 l= 1 prim: OCTET STRING [HEX DUMP]:07 - /// 60:d=1 hl=2 l= 65 prim: OCTET STRING [HEX DUMP]:0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 - /// 127:d=1 hl=2 l= 33 prim: INTEGER :FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - /// 162:d=1 hl=2 l= 1 prim: INTEGER :01 - let ecPEM = """ - -----BEGIN EC PRIVATE KEY----- - MIIBEwIBAQQgiOURdsStmumMgM2c29TlUxEdNxrQns8VPeM0sV08MtKggaUwgaIC - AQEwLAYHKoZIzj0BAQIhAP////////////////////////////////////7///wv - MAYEAQAEAQcEQQR5vmZ++dy7rFWgYpXOhwsHApv82y3OKNlZ8oFbFvgXmEg62ncm - o8RlXaT7/A4RCKj9F7RIpoVUGZxH0I/7ENS4AiEA/////////////////////rqu - 3OavSKA7v9JejNA2QUECAQGhRANCAASDsnwEULWLn8HV8iobNGNAdze/SbwbehJ3 - l+gvkHpYQ2tMD9d4NTMDKFTxPUN+w0ktADgGaPhd2flQ2dNL7nFT - -----END EC PRIVATE KEY----- - """ - let ecPEM2 = """ - -----BEGIN EC PRIVATE KEY----- - MHQCAQEEIFTQEjBp0zAIiafoD6+xwBS/kAvc4qq0BVZ1QTk//EguoAcGBSuBBAAK - oUQDQgAEmLNqAvsnenwfMz8+U5MUGb4zwhfxVBjRqn7Bqa/CCVPtsqSMfhzaE30u - OQlpl7VjL/jrZYpUv8aPRfTBSn396w== - -----END EC PRIVATE KEY----- - """ - - let ecParams = """ - -----BEGIN EC PARAMETERS----- - BgUrgQQACg== - -----END EC PARAMETERS----- - """ - - let ecPEMPrivate = """ - -----BEGIN EC PRIVATE KEY----- - MHQCAQEEINMfarC/mmrd3GKaOfl+7iXffsdg4MqMa4HY5wkBDilooAcGBSuBBAAK - oUQDQgAEJ9kHLQX2sVEh14Duq23w5af30636vUx93jVsMIDhONwwuQc2N7mv4/oY - 8oB3EPTRyh+o+6J+9qXI1VaJjvSr5Q== - -----END EC PRIVATE KEY----- - """ - let ecPEMPublic = """ - -----BEGIN PUBLIC KEY----- - MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJ9kHLQX2sVEh14Duq23w5af30636vUx9 - 3jVsMIDhONwwuQc2N7mv4/oY8oB3EPTRyh+o+6J+9qXI1VaJjvSr5Q== - -----END PUBLIC KEY----- - """ - - let pemBase64String = ecPEM2.split(separator: "\n").dropFirst().dropLast().joined() - let pemData = Data(base64Encoded: pemBase64String)! - - print(pemData.toHexString()) - - //30820113 - // 020101 - // 042088e51176c4ad9ae98c80cd9cdbd4e553111d371ad09ecf153de334b15d3c32d2a081a53081a2 - // 020101 - // 302c06072a8648ce3d0101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f - // 3006 - // 040100 - // 040107 - // 04410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 - // 022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0//364141 - // 020101 - // a144 - // 0342 - // 00 - // 0483b27c0450b58b9fc1d5f22a1b3463407737bf49bc1b7a127797e82f907a58436b4c0fd7783533032854f13d437ec3492d00380668f85dd9f950d9d34bee7153 - - - //3074 - // 020101 - // 042054d0123069d3300889a7e80fafb1c014bf900bdce2aab405567541393ffc - //482ea00706052b8104000aa1440342000498b36a02fb277a7c1f333f3e53931419be33c217f15418d1aa7ec1a9afc20953edb2a48c7e1cda137d2e39096997b5632ff8eb658a54bfc68f45f4c14a7dfdeb - - let parsed = try ASN1.Decoder.decode(data: pemData) - - print(parsed) - -// if case .octetString(let rawData) = parsed { -// let edPrivate = try Curve25519.Signing.PrivateKey(rawRepresentation: rawData) -// print(edPrivate) -// } - } - +/// RSA Object Identifier --> 2a 86 48 86 f7 0d 01 01 01 (bit length independent, pub/priv key independent) +/// ECDSA P384 --> 2a 86 48 ce 3d 02 01 +// func testPemParsing() throws { +// +//// let pem = """ +//// -----BEGIN PUBLIC KEY----- +//// MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcZ/r0nvJyHUUstIB5BqCUJ1CC +//// Cd1nzle4bEpPQJ/S0Wn7mV2FDAeh+UcbVhZu9n+5zypYNjeZKapPqBLoT8eCK51y +//// Kpzeb8LuEm3P8PK4xN18XBrIF1GprN8IIgSdK9f5SwnemutcURrY+PlWnvj7N5s/ +//// 03RlJA3/NHVXpPW/VQIDAQAB +//// -----END PUBLIC KEY----- +//// """ +// +// let pem = """ +// -----BEGIN PRIVATE KEY----- +// MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQDp0Whyqa8KmdvK +// 0MsQGJEBzDAEHAZc0C6cr0rkb6Xwo+yB5kjZBRDORk0UXtYGE1pYt4JhUTmMzcWO +// v2xTIsdbVMQlNtput2U8kIqS1cSTkX5HxOJtCiIzntMzuR/bGPSOexkyFQ8nCUqb +// ROS7cln/ixprra2KMAKldCApN3ue2jo/JI1gyoS8sekhOASAa0ufMPpC+f70sc75 +// Y53VLnGBNM43iM/2lsK+GI2a13d6rRy86CEM/ygnh/EDlyNDxo+SQmy6GmSv/lmR +// xgWQE2dIfK504KIxFTOphPAQAr9AsmcNnCQLhbz7YTsBz8WcytHGQ0Z5pnBQJ9AV +// CX9E6DFHetvs0CNLVw1iEO06QStzHulmNEI/3P8I1TIxViuESJxSu3pSNwG1bSJZ +// +Qee24vvlz/slBzK5gZWHvdm46v7vl5z7SA+whncEtjrswd8vkJk9fI/YTUbgOC0 +// HWMdc2t/LTZDZ+LUSZ/b2n5trvdJSsOKTjEfuf0wICC08pUUk8MCAwEAAQKCAYEA +// ywve+DQCneIezHGk5cVvp2/6ApeTruXalJZlIxsRr3eq2uNwP4X2oirKpPX2RjBo +// NMKnpnsyzuOiu+Pf3hJFrTpfWzHXXm5Eq+OZcwnQO5YNY6XGO4qhSNKT9ka9Mzbo +// qRKdPrCrB+s5rryVJXKYVSInP3sDSQ2IPsYpZ6GW6Mv56PuFCpjTzElzejV7M0n5 +// 0bRmn+MZVMVUR54KYiaCywFgUzmr3yfs1cfcsKqMRywt2J58lRy/chTLZ6LILQMv +// 4V01neVJiRkTmUfIWvc1ENIFM9QJlky9AvA5ASvwTTRz8yOnxoOXE/y4OVyOePjT +// cz9eumu9N5dPuUIMmsYlXmRNaeGZPD9bIgKY5zOlfhlfZSuOLNH6EHBNr6JAgfwL +// pdP43sbg2SSNKpBZ0iSMvpyTpbigbe3OyhnFH/TyhcC2Wdf62S9/FRsvjlRPbakW +// YhKAA2kmJoydcUDO5ccEga8b7NxCdhRiczbiU2cj70pMIuOhDlGAznyxsYbtyxaB +// AoHBAPy6Cbt6y1AmuId/HYfvms6i8B+/frD1CKyn+sUDkPf81xSHV7RcNrJi1S1c +// V55I0y96HulsR+GmcAW1DF3qivWkdsd/b4mVkizd/zJm3/Dm8p8QOnNTtdWvYoEB +// VzfAhBGaR/xflSLxZh2WE8ZHQ3IcRCXV9ZFgJ7PMeTprBJXzl0lTptvrHyo9QK1v +// obLrL/KuXWS0ql1uSnJr1vtDI5uW8WU4GDENeU5b/CJHpKpjVxlGg+7pmLknxlBl +// oBnZnQKBwQDs2Ky29qZ69qnPWowKceMJ53Z6uoUeSffRZ7xuBjowpkylasEROjuL +// nyAihIYB7fd7R74CnRVYLI+O2qXfNKJ8HN+TgcWv8LudkRcnZDSvoyPEJAPyZGfr +// olRCXD3caqtarlZO7vXSAl09C6HcL2KZ8FuPIEsuO0Aw25nESMg9eVMaIC6s2eSU +// NUt6xfZw1JC0c+f0LrGuFSjxT2Dr5WKND9ageI6afuauMuosjrrOMl2g0dMcSnVz +// KrtYa7Wi1N8CgcBFnuJreUplDCWtfgEen40f+5b2yAQYr4fyOFxGxdK73jVJ/HbW +// wsh2n+9mDZg9jIZQ/+1gFGpA6V7W06dSf/hD70ihcKPDXSbloUpaEikC7jxMQWY4 +// uwjOkwAp1bq3Kxu21a+bAKHO/H1LDTrpVlxoJQ1I9wYtRDXrvBpxU2XyASbeFmNT +// FhSByFn27Ve4OD3/NrWXtoVwM5/ioX6ZvUcj55McdTWE3ddbFNACiYX9QlyOI/TY +// bhWafDCPmU9fj6kCgcEAjyQEfi9jPj2FM0RODqH1zS6OdG31tfCOTYicYQJyeKSI +// /hAezwKaqi9phHMDancfcupQ89Nr6vZDbNrIFLYC3W+1z7hGeabMPNZLYAs3rE60 +// dv4tRHlaNRbORazp1iTBmvRyRRI2js3O++3jzOb2eILDUyT5St+UU/LkY7R5EG4a +// w1df3idx9gCftXufDWHqcqT6MqFl0QgIzo5izS68+PPxitpRlR3M3Mr4rCU20Rev +// blphdF+rzAavYyj1hYuRAoHBANmxwbq+QqsJ19SmeGMvfhXj+T7fNZQFh2F0xwb2 +// rMlf4Ejsnx97KpCLUkoydqAs2q0Ws9Nkx2VEVx5KfUD7fWhgbpdnEPnQkfeXv9sD +// vZTuAoqInN1+vj1TME6EKR/6D4OtQygSNpecv23EuqEvyXWqRVsRt9Qd2B0H4k7h +// gnjREs10u7zyqBIZH7KYVgyh27WxLr859ap8cKAH6Fb+UOPtZo3sUeeume60aebn +// 4pMwXeXP+LO8NIfRXV8mgrm86g== +// -----END PRIVATE KEY----- +// """ +// +//// /// EC P256 Public Key +//// let pem = """ +//// -----BEGIN PUBLIC KEY----- +//// MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEb4nB0k8CBVnKCHVHkxuXAkSlZuO5 +//// Nsev1rzcRv5QHiJuWUKomFGadQlMSGwoDOHEDdW3ujcA6t0ADteHw6KrZg== +//// -----END PUBLIC KEY----- +//// """ +// +//// /// EC P384 Public Key +//// let pem = """ +//// -----BEGIN PUBLIC KEY----- +//// MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEBwY0l7mq7hSBEZRld5ISWfSoFsYN3wwM +//// hdD3cMU95DmYXzbqVHB4dCfsy7bexm4h9c0zs4CyTPzy3DV3vfmv1akQJIQv7l08 +//// lx/YXNeGXTN4Gr9r4rwA5GvRl1p6plPL +//// -----END PUBLIC KEY----- +//// """ +// +//// /// EC P521 Public Key +//// let pem = """ +//// -----BEGIN PUBLIC KEY----- +//// MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAp3v1UQWvSyQnkAUEBu+x/7ZrPtNJ +//// SCUk9kMvuZMyGP1idwvspALuJjzrSFFlXObjlOjxucSbWhTYF/o3nc0XzpAA3dxA +//// BYiMqH9vrVePoJMpv+DMdkUiUJ/WqHSOu9bJEi1h4fdqh5HHx4QZJY/iX/59VAi1 +//// uSbAhALvbdGFbVpkcOs= +//// -----END PUBLIC KEY----- +//// """ +// +// /// EC P256 Private Key +//// let pem = """ +//// -----BEGIN PRIVATE KEY----- +//// MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgZjQLlzempZx7YF1F +//// +MK1HWZTNgLcC1MAufb/2/YZYk6hRANCAAQwgn0PfkIHiZ/K+3zA//CoDqU2PqDc +//// aA3U5R68jmlZQITvMyBlMJl9Mjh0biIe88dAfRKeUm9FVMD2ErJ/006V +//// -----END PRIVATE KEY----- +//// """ +// +// /// PEMP384PKCS8 +//// let pem = """ +//// -----BEGIN PRIVATE KEY----- +//// MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDB7ERKhMR+mvz1NQ+oL +//// i6ZJMACOcwbUetWcNnB4Mnx3j4XuhpkkHEW8E1+rXyjZ3UmhZANiAASYH+emlyXM +//// kBSFJl0BiopDVuIIR47M4pLl00YNnuu/Rp5VHeVAHrP67i2Q92u5fk34eOSwQvkO +//// VvktWsgtzAomIam4SHqE9bhvrHy6kW6QzxlERHTL+YkXEX8c6t8VOxk= +//// -----END PRIVATE KEY----- +//// """ // -// func testSecp256k1_Pem_Parsing_Private() throws { -// let parsed = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.SECP256k1_KeyPair.PRIVATE) +// let chunks = pem.split(separator: "\n") +// guard chunks.count > 3, +// let f = chunks.first, f.hasPrefix("-----BEGIN"), +// let l = chunks.last, l.hasSuffix("-----") else { +// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) +// } // -// print(parsed) -// } - - func testImportSecp256k1PEM() throws { - let secp256k1Public = try Secp256k1PublicKey(pem: TestPEMKeys.SECP256k1_KeyPair.PUBLIC, asType: Secp256k1PublicKey.self) - - print(secp256k1Public) - - let secp256k1Private = try Secp256k1PrivateKey(pem: TestPEMKeys.SECP256k1_KeyPair.PRIVATE, asType: Secp256k1PrivateKey.self) - - print(secp256k1Private) - } - - /// -----BEGIN PGP PUBLIC KEY BLOCK----- - /// Comment: C459 E542 8084 7C93 79BE 9AED DA30 E629 61F6 0A75 - /// Comment: Alice Wonderland - /// - /// xsDNBGH7EL8BDADovR5cjh9P26RJ2uNxHuaEmdSFTY6q2uE5s4C6G+JEmtyuqhC9 - /// HEHgl7hv9LbsskLs50J0cCH9KQzMSl2OxztVGR8ABV06oDB+7fhHEPXNA4m1cLmQ - /// zGCp9uDxCs3tuDJRkEMSo97T6AnQwDsl5rBBMqR9c/B7Ozml1aER6ehtxSQt7tuu - /// x/9oD+9zFyUsBOuO20d/Km629h6IHfF+BadbJpzAqHunq+w2P4ks7XYlhFJdhMIq - /// W0h31rI1CO4tM+DG7+6Osz6EJeHWZOc9tWM/5YxmJOA7SZU4t+yedif4bzC4+aCH - /// W2AYlrWKivNOe4n46u1J+xlCtnLyK9Si39ylDuem118diaW1Qs99PkTbWawagYyc - /// c+0flTYeWugLxc2LDUfq9b6r7tfu9hyez0TghdRwlvrQlnZCmEt/Ndg0YF0N3BFE - /// dAzdpsiddEytH28L7hwHE5lECam4mGxBe8uNGYlDu8Viq7IYhyfCM0CNGlEwUQIW - /// I7ahSbKTX66aZxcAEQEAAc0lTG93ZWxsIFRvbXMgPGxvd2VsbHMudmF1bHRAZ21h - /// aWwuY29tPsLBFAQTAQoAPhYhBMRZ5UKAhHyTeb6a7dow5ilh9gp1BQJh+xC/AhsD - /// BQkDwmcABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJENow5ilh9gp1sNoMAItC - /// peoNv5MLrf5XJzP+bi+qmyAkiQSQ+0Jd17G1bUgrmpjeWXUqxu3fWgdxC6+CQLM9 - /// Fj69v11G1nrNlII0vyUN0nxPf9LS5qPMQKXZeAvT+lYrPaNWoE4ShI7MnJhxbME9 - /// TlQNikjOYgWt5dNlO+XqWAqP9ECQ0D2x2ulypVvhYPpvslp0+dQJGfIteTzqHHIY - /// Cu7drWh5Sjy2pvIKOIjjrKapjwqidy6laDi4NDhbu/JWp4im1ZRpIU6qTZgH4b+U - /// kCiAScNbnkYWtlIJ73j+Mh62FzZFQ+lSlVI8Fe/POyCwphVUw9smaEMO1WCsg0zP - /// LLAfnVLhWXdaB1QfchlWU1C/zVtnyCZvkVzDTFCa4IyBrAqUCnXfJHOgivtUU4rl - /// FvgynrDmeKjUqxJsVpEDS524nxR7aVdnfj34879SlJdliHeuwgpYF1q3eQYJMrR/ - /// wDCRBxbGpHTCOVjtU6GEeE9mV93SwVFAFHokD/iJMNTmGiUxFubHQXqCuAKuCc7A - /// zQRh+xC/AQwA0NZs9RjrGAicIFIp6C7NHheyFDL8tet5ZDPO2Lya22AXgnWo3/bs - /// QGXOlxhHJB7TK3Ma5wHAUKJ4BEvxpMtSwHnkFf/EAFZug2AXIvhJpdT8j/Lct6er - /// VusrPxfDmlTH0QeKl3IklnvowyO3r6VeI2Lxga0gWlV+/gRq0vzwXM4vqeXzjNFo - /// cCuNq4jSFT+zztYkud8GbAULBB5oeAp1Dhp+Uk84tu2Lg8rbBhK/H/ax4ozUrWi2 - /// G6azGx9psW9yq+LnQXaCSeGTn8XMqXzuwiD87TZgvuih/8iyMDoaFnuSKCw4v1WQ - /// 8wWusZ2e0a05SCiRpYDlv+CJ93J5F1ApZXjD9NpYcU0O53zl+wqqNbj1HtxoGPrT - /// EHvKPYZru/Dtea+sAxEXpYpUXFamQq4zIaI+dagD3vzSmFLRuCtaZElHhsS3t91K - /// tQBKon1ZEN/VwdO7tix6gfDMMa3BpnllI2eaw2X+Ucdkm/jJHuPoxfy1lbFP8byy - /// fDXvhR8Pnk8TABEBAAHCwPwEGAEKACYWIQTEWeVCgIR8k3m+mu3aMOYpYfYKdQUC - /// YfsQvwIbDAUJA8JnAAAKCRDaMOYpYfYKddh5DADGLKm9AmtCh7bUR+r+MKdCyjTO - /// LSiu0WACRUHIw+RLu5J5/haa7xZKPo6iN955oUS3j9CK0NTr/+ZxdDFwVc7kAjOn - /// eoZefac0CFRtLO26LQcVh5jc6YV0ZVtchvbnWCOfwtsvVfsQUCo7oIfP2CacEGq2 - /// EIqYLTJ7leVgo3AqlR5MmPA+umMKVcb/KDkesMnhgThw3F+81cocRhxWVlNQam0/ - /// PAj2uprXt+yWU8K94gojmolBuSdBBMZGArjBr/oCAhBrWarg4gEnC0tGQBBLU1Us - /// YEdv+2OYokrlIU96P2mtCDX+9GId+idUlgEPc+CQr3Um9W/syyxGI2e2wSlAlkjh - /// +h84GvLvZpM9HU4HrHF5AxmXoEe2BF7ICHHju0vdignpEdtQ/XHckSLlxcJz8i2S - /// XkMi7m1i5U0OWEXVr+Z3jeW2HVVEvEJ7aXL3oLLAVz3TROFY0M41zjrstyjg0sg5 - /// 5H93wgN5hgZ8MeDFEWbEh3p7e/MP9I/lo70bkA0= - /// =n56n - /// -----END PGP PUBLIC KEY BLOCK----- -// func testOpen_ASC_PGP_PublicKey() throws { -// let urls = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask) -// let downloadsFolder = urls[0] +// //print("Attempting to decode: \(chunks[1.. Date: Sat, 18 Jun 2022 18:38:03 +0530 Subject: [PATCH 18/52] Implemented exportPrivateKeyPEMRaw methods. --- .../Keys/Types/Ed25519/Ed25519.swift | 57 ++++++++++++++++++- .../LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift | 46 +++++++++++++++ .../Keys/Types/Secp256k1/Secp256k1.swift | 56 +++++++++++++++++- 3 files changed, 157 insertions(+), 2 deletions(-) diff --git a/Sources/LibP2PCrypto/Keys/Types/Ed25519/Ed25519.swift b/Sources/LibP2PCrypto/Keys/Types/Ed25519/Ed25519.swift index ecc149d..4bd9cf7 100644 --- a/Sources/LibP2PCrypto/Keys/Types/Ed25519/Ed25519.swift +++ b/Sources/LibP2PCrypto/Keys/Types/Ed25519/Ed25519.swift @@ -149,6 +149,30 @@ extension Curve25519.Signing.PublicKey:DERCodable { public func privateKeyDER() throws -> Array { throw NSError(domain: "Public Key doesn't have private DER representation", code: 0) } + + public func exportPublicKeyPEM(withHeaderAndFooter: Bool) throws -> Array { + let publicDER = try self.publicKeyDER() + + let asnNodes:ASN1.Node = .sequence(nodes: [ + .sequence(nodes: [ + .objectIdentifier(data: Data(Self.primaryObjectIdentifier)), + ]), + .bitString(data: Data( publicDER )) + ]) + + let base64String = ASN1.Encoder.encode(asnNodes).toBase64() + let bodyString = base64String.chunks(ofCount: 64).joined(separator: "\n") + let bodyUTF8Bytes = bodyString.bytes + + if withHeaderAndFooter { + let header = PEM.PEMType.publicKey.headerBytes + [0x0a] + let footer = [0x0a] + PEM.PEMType.publicKey.footerBytes + + return header + bodyUTF8Bytes + footer + } else { + return bodyUTF8Bytes + } + } } extension Curve25519.Signing.PrivateKey:DERCodable { @@ -171,7 +195,38 @@ extension Curve25519.Signing.PrivateKey:DERCodable { } public func privateKeyDER() throws -> Array { - self.rawRepresentation.bytes + ASN1.Encoder.encode( + ASN1.Node.octetString(data: Data( self.rawRepresentation )) + ) + } + + public func exportPrivateKeyPEMRaw() throws -> Array { + let privKey = try privateKeyDER() + + let asnNodes:ASN1.Node = .sequence(nodes: [ + .integer(data: Data(hex: "0x00")), + .sequence(nodes: [ + .objectIdentifier(data: Data(Self.primaryObjectIdentifier) ) + ]), + .octetString(data: Data(privKey) ) + ]) + + return ASN1.Encoder.encode(asnNodes) + } + + public func exportPrivateKeyPEM(withHeaderAndFooter: Bool) throws -> Array { + let base64String = try self.exportPrivateKeyPEMRaw().toBase64() + let bodyString = base64String.chunks(ofCount: 64).joined(separator: "\n") + let bodyUTF8Bytes = bodyString.bytes + + if withHeaderAndFooter { + let header = PEM.PEMType.privateKey.headerBytes + [0x0a] + let footer = [0x0a] + PEM.PEMType.privateKey.footerBytes + + return header + bodyUTF8Bytes + footer + } else { + return bodyUTF8Bytes + } } } diff --git a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift index ff9f1a6..81fc80d 100644 --- a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift +++ b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift @@ -28,6 +28,23 @@ extension RSAPublicKey:DERCodable { init(privateDER: Array) throws { throw NSError(domain: "Can't instantiate private key from public DER representation", code: 0) } + + public func exportPublicKeyPEM(withHeaderAndFooter: Bool) throws -> Array { + let publicDER = try self.publicKeyDER() + + let base64String = publicDER.toBase64() + let bodyString = base64String.chunks(ofCount: 64).joined(separator: "\n") + let bodyUTF8Bytes = bodyString.bytes + + if withHeaderAndFooter { + let header = PEM.PEMType.publicKey.headerBytes + [0x0a] + let footer = [0x0a] + PEM.PEMType.publicKey.footerBytes + + return header + bodyUTF8Bytes + footer + } else { + return bodyUTF8Bytes + } + } } extension RSAPrivateKey: DERCodable { @@ -51,4 +68,33 @@ extension RSAPrivateKey: DERCodable { init(privateDER: Array) throws { try self.init(rawRepresentation: Data(privateDER)) } + + public func exportPrivateKeyPEMRaw() throws -> Array { + let privateDER = try self.privateKeyDER() + let asnNodes:ASN1.Node = .sequence(nodes: [ + .integer(data: Data(hex: "0x00")), + .sequence(nodes: [ + .objectIdentifier(data: Data(Self.primaryObjectIdentifier)), + .null + ]), + .octetString(data: Data( privateDER )) + ]) + + return ASN1.Encoder.encode(asnNodes) + } + + public func exportPrivateKeyPEM(withHeaderAndFooter: Bool) throws -> Array { + let base64String = try self.exportPrivateKeyPEMRaw().toBase64() + let bodyString = base64String.chunks(ofCount: 64).joined(separator: "\n") + let bodyUTF8Bytes = bodyString.bytes + + if withHeaderAndFooter { + let header = PEM.PEMType.privateKey.headerBytes + [0x0a] + let footer = [0x0a] + PEM.PEMType.privateKey.footerBytes + + return header + bodyUTF8Bytes + footer + } else { + return bodyUTF8Bytes + } + } } diff --git a/Sources/LibP2PCrypto/Keys/Types/Secp256k1/Secp256k1.swift b/Sources/LibP2PCrypto/Keys/Types/Secp256k1/Secp256k1.swift index e04d76b..4940d3c 100644 --- a/Sources/LibP2PCrypto/Keys/Types/Secp256k1/Secp256k1.swift +++ b/Sources/LibP2PCrypto/Keys/Types/Secp256k1/Secp256k1.swift @@ -126,12 +126,37 @@ extension Secp256k1PublicKey:DERCodable { } public func publicKeyDER() throws -> Array { - self.rawRepresentation.bytes + [0x04] + self.rawRepresentation } public func privateKeyDER() throws -> Array { throw NSError(domain: "Public Key doesn't have private DER representation", code: 0) } + + public func exportPublicKeyPEM(withHeaderAndFooter: Bool) throws -> Array { + let publicDER = try self.publicKeyDER() + + let asnNodes:ASN1.Node = .sequence(nodes: [ + .sequence(nodes: [ + .objectIdentifier(data: Data(Self.primaryObjectIdentifier)), + .objectIdentifier(data: Data(Self.secondaryObjectIdentifier!)) + ]), + .bitString(data: Data( publicDER )) + ]) + + let base64String = ASN1.Encoder.encode(asnNodes).toBase64() + let bodyString = base64String.chunks(ofCount: 64).joined(separator: "\n") + let bodyUTF8Bytes = bodyString.bytes + + if withHeaderAndFooter { + let header = PEM.PEMType.publicKey.headerBytes + [0x0a] + let footer = [0x0a] + PEM.PEMType.publicKey.footerBytes + + return header + bodyUTF8Bytes + footer + } else { + return bodyUTF8Bytes + } + } } extension Secp256k1PrivateKey:DERCodable { @@ -154,5 +179,34 @@ extension Secp256k1PrivateKey:DERCodable { self.rawRepresentation.bytes } + public func exportPrivateKeyPEMRaw() throws -> Array { + let publicDER = try self.publicKeyDER() + + let pubKeyBitString:ASN1.Node = .bitString(data: Data( publicDER )) + + let asnNodes:ASN1.Node = .sequence(nodes: [ + .integer(data: Data(hex: "0x01")), + .octetString(data: self.rawRepresentation), + .ecObject(data: Data(Self.primaryObjectIdentifier)), + .ecBits(data: Data(ASN1.Encoder.encode(pubKeyBitString))) + ]) + + return ASN1.Encoder.encode(asnNodes) + } + + public func exportPrivateKeyPEM(withHeaderAndFooter: Bool) throws -> Array { + let base64String = try self.exportPrivateKeyPEMRaw().toBase64() + let bodyString = base64String.chunks(ofCount: 64).joined(separator: "\n") + let bodyUTF8Bytes = bodyString.bytes + + if withHeaderAndFooter { + let header = PEM.PEMType.ecPrivateKey.headerBytes + [0x0a] + let footer = [0x0a] + PEM.PEMType.ecPrivateKey.footerBytes + + return header + bodyUTF8Bytes + footer + } else { + return bodyUTF8Bytes + } + } } From 84d726aa239cb493501762086e77be875b994038 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 18 Jun 2022 18:50:05 +0530 Subject: [PATCH 19/52] implemented exportPublicKeyPEMRaw and exportPrivateKeyPEMRaw methods for internal use with encrypted PEMs --- Sources/LibP2PCrypto/PEM/DER.swift | 60 +++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/Sources/LibP2PCrypto/PEM/DER.swift b/Sources/LibP2PCrypto/PEM/DER.swift index 7d10082..3bd50c7 100644 --- a/Sources/LibP2PCrypto/PEM/DER.swift +++ b/Sources/LibP2PCrypto/PEM/DER.swift @@ -84,6 +84,7 @@ public extension DERDecodable { // Proceed with the unencrypted PEM (can public PEM keys be encrypted as well, wouldn't really make sense but idk if we should support it)? let der = try PEM.decodePrivateKeyPEM(Data(decryptedPEM), expectedPrimaryObjectIdentifier: Key.primaryObjectIdentifier, expectedSecondaryObjectIdentifier: Key.secondaryObjectIdentifier) + try self.init(privateDER: der) } } @@ -99,8 +100,11 @@ public protocol DEREncodable { func publicKeyDER() throws -> Array func privateKeyDER() throws -> Array + /// The raw ASN1 Encoded PEM data without headers, footers and line breaks + func exportPrivateKeyPEMRaw() throws -> Array + /// PublicKey PEM Export Functions - func exportPublicKeyPEM(withHeaderAndFooter:Bool) throws -> Array + func exportPublicKeyPEM(withHeaderAndFooter:Bool) throws -> Array func exportPublicKeyPEMString(withHeaderAndFooter:Bool) throws -> String /// PrivateKey PEM Export Functions @@ -109,17 +113,41 @@ public protocol DEREncodable { } public extension DEREncodable { - func exportPublicKeyPEM(withHeaderAndFooter:Bool = true) throws -> Array { + + internal func exportPublicKeyPEMRaw() throws -> Array { let publicDER = try self.publicKeyDER() - let asnNodes:ASN1.Node = .sequence(nodes: [ - .sequence(nodes: [ - .objectIdentifier(data: Data(Self.primaryObjectIdentifier)), - .null - ]), - .bitString(data: Data( publicDER )) - ]) + let secondaryObject:ASN1.Node? + if Self.primaryObjectIdentifier == RSAPublicKey.primaryObjectIdentifier { + secondaryObject = .null + } else if Self.primaryObjectIdentifier == Secp256k1PublicKey.primaryObjectIdentifier { + secondaryObject = .objectIdentifier(data: Data(Self.secondaryObjectIdentifier!)) + } else { + secondaryObject = nil + } - let base64String = ASN1.Encoder.encode(asnNodes).toBase64() + let asnNodes:ASN1.Node + if let secObj = secondaryObject { + asnNodes = .sequence(nodes: [ + .sequence(nodes: [ + .objectIdentifier(data: Data(Self.primaryObjectIdentifier)), + secObj + ]), + .bitString(data: Data( publicDER )) + ]) + } else { + asnNodes = .sequence(nodes: [ + .sequence(nodes: [ + .objectIdentifier(data: Data(Self.primaryObjectIdentifier)) + ]), + .bitString(data: Data( publicDER )) + ]) + } + + return ASN1.Encoder.encode(asnNodes) + } + + func exportPublicKeyPEM(withHeaderAndFooter:Bool = true) throws -> Array { + let base64String = try self.exportPublicKeyPEMRaw().toBase64() let bodyString = base64String.chunks(ofCount: 64).joined(separator: "\n") let bodyUTF8Bytes = bodyString.bytes @@ -141,18 +169,22 @@ public extension DEREncodable { return pemAsString } - func exportPrivateKeyPEM(withHeaderAndFooter:Bool = true) throws -> Array { + func exportPrivateKeyPEMRaw() throws -> Array { let privateDER = try self.privateKeyDER() let asnNodes:ASN1.Node = .sequence(nodes: [ .integer(data: Data(hex: "0x00")), .sequence(nodes: [ .objectIdentifier(data: Data(Self.primaryObjectIdentifier)), - .null + //.null ]), .octetString(data: Data( privateDER )) ]) - - let base64String = ASN1.Encoder.encode(asnNodes).toBase64() + + return ASN1.Encoder.encode(asnNodes) + } + + func exportPrivateKeyPEM(withHeaderAndFooter:Bool = true) throws -> Array { + let base64String = try self.exportPrivateKeyPEMRaw().toBase64() let bodyString = base64String.chunks(ofCount: 64).joined(separator: "\n") let bodyUTF8Bytes = bodyString.bytes From b759d67cbe89d68d3513c898d44926769ca98b20 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 18 Jun 2022 18:51:15 +0530 Subject: [PATCH 20/52] Preliminary support for exporting encrypted PEMs. Only RSA tested at the moment. --- Sources/LibP2PCrypto/PEM/PEM.swift | 146 ++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 1 deletion(-) diff --git a/Sources/LibP2PCrypto/PEM/PEM.swift b/Sources/LibP2PCrypto/PEM/PEM.swift index 345eb11..32f03e9 100644 --- a/Sources/LibP2PCrypto/PEM/PEM.swift +++ b/Sources/LibP2PCrypto/PEM/PEM.swift @@ -384,6 +384,38 @@ extension PEM { return EncryptedPEM(objectIdentifer: objID.bytes, ciphertext: octets.bytes, pbkdfAlgorithm: pbkdf, cipherAlgorithm: cipher) } + + internal static func encryptPEM(_ pem:Data, withPassword password:String, usingPBKDF pbkdf:PBKDFAlgorithm = .pbkdf2(salt: try! LibP2PCrypto.randomBytes(length: 8), iterations: 2048), andCipher cipher:CipherAlgorithm = .aes_128_cbc(iv: try! LibP2PCrypto.randomBytes(length: 16))) throws -> Data { + + // Generate Encryption Key from Password + let key = try pbkdf.deriveKey(password: password, ofLength: cipher.desiredKeyLength) + + // Encrypt Plaintext + let ciphertext = try cipher.encrypt(bytes: pem.bytes, withKey: key) + + // Encode Encrypted PEM (including pbkdf and cipher algos used) + let nodes:ASN1.Node = .sequence(nodes: [ + .sequence(nodes: [ + .objectIdentifier(data: Data(hex: "2a864886f70d01050d")), + .sequence(nodes: [ + try pbkdf.encodePBKDF(), + try cipher.encodeCipher() + ]) + ]), + .octetString(data: Data(ciphertext)) + ]) + + let encoded = ASN1.Encoder.encode(nodes) + + let base64 = "\n" + encoded.toBase64().split(intoChunksOfLength: 64).joined(separator: "\n") + "\n" + + return Data(PEM.PEMType.encryptedPrivateKey.headerBytes + base64.bytes + PEM.PEMType.encryptedPrivateKey.footerBytes) + } + + internal static func encryptPEMString(_ pem:Data, withPassword password:String, usingPBKDF pbkdf:PBKDFAlgorithm = .pbkdf2(salt: try! LibP2PCrypto.randomBytes(length: 8), iterations: 2048), andCipher cipher:CipherAlgorithm = .aes_128_cbc(iv: try! LibP2PCrypto.randomBytes(length: 16))) throws -> String { + let data = try PEM.encryptPEM(pem, withPassword: password, usingPBKDF: pbkdf, andCipher: cipher) + return String(data: data, encoding: .utf8)! + } } @@ -407,11 +439,45 @@ extension PEM { func deriveKey(password:String, ofLength keyLength:Int, usingHashVarient variant:HMAC.Variant = .sha1) throws -> [UInt8] { switch self { case .pbkdf2(let salt, let iterations): - return try PKCS5.PBKDF2(password: password.bytes, salt: salt, iterations: iterations, keyLength: keyLength, variant: variant).calculate() + //print("Salt: \(salt), Iterations: \(iterations)") + let key = try PKCS5.PBKDF2(password: password.bytes, salt: salt, iterations: iterations, keyLength: keyLength, variant: variant).calculate() + //print(key) + return key //default: // throw Error.invalidPEMFormat } } + + var objectIdentifier:[UInt8] { + switch self { + case .pbkdf2: + return [42, 134, 72, 134, 247, 13, 1, 5, 12] + } + } + + var salt:[UInt8] { + switch self { + case .pbkdf2(let salt, _): + return salt + } + } + + var iterations:Int { + switch self { + case .pbkdf2(_, let iterations): + return iterations + } + } + + func encodePBKDF() throws -> ASN1.Node { + return .sequence(nodes: [ + .objectIdentifier(data: Data(self.objectIdentifier)), + .sequence(nodes: [ + .octetString(data: Data(self.salt)), + .integer(data: Data(self.iterations.bytes(totalBytes: 2))) + ]) + ]) + } } /// Decodes the PBKDF ASN1 Block in an Encrypted Private Key PEM file @@ -467,13 +533,24 @@ extension PEM { func decrypt(bytes: [UInt8], withKey key:[UInt8]) throws -> [UInt8] { switch self { case .aes_128_cbc(let iv): + //print("128 IV: \(iv)") return try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(bytes) case .aes_256_cbc(let iv): + //print("256 IV: \(iv)") return try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(bytes) //default: //throw Error.invalidPEMFormat } } + + func encrypt(bytes: [UInt8], withKey key:[UInt8]) throws -> [UInt8] { + switch self { + case .aes_128_cbc(let iv): + return try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(bytes) + case .aes_256_cbc(let iv): + return try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(bytes) + } + } /// The key length used for this Cipher strategy /// - Note: we need this information when deriving the key using our PBKDF strategy @@ -483,6 +560,31 @@ extension PEM { case .aes_256_cbc: return 32 } } + + var objectIdentifier:[UInt8] { + switch self { + case .aes_128_cbc: + return [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02] + case .aes_256_cbc: + return [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2a] + } + } + + var iv:[UInt8] { + switch self { + case .aes_128_cbc(let iv): + return iv + case .aes_256_cbc(let iv): + return iv + } + } + + func encodeCipher() throws -> ASN1.Node { + return .sequence(nodes: [ + .objectIdentifier(data: Data(self.objectIdentifier)), + .octetString(data: Data(self.iv)) + ]) + } } /// Decodes the Cipher ASN1 Block in an Encrypted Private Key PEM file @@ -505,3 +607,45 @@ extension PEM { return try CipherAlgorithm(objID: objID.bytes, iv: initialVector.bytes) } } + + +#if canImport(Darwin) +import Darwin +#elseif canImport(Glibc) +import Glibc +#elseif canImport(ucrt) +import ucrt +#endif + +extension FixedWidthInteger { + @inlinable + func bytes(totalBytes: Int = MemoryLayout.size) -> Array { + arrayOfBytes(value: self.littleEndian, length: totalBytes) + // TODO: adjust bytes order + // var value = self.littleEndian + // return withUnsafeBytes(of: &value, Array.init).reversed() + } +} + +@_specialize(where T == Int) +@_specialize(where T == UInt) +@_specialize(where T == UInt8) +@_specialize(where T == UInt16) +@_specialize(where T == UInt32) +@_specialize(where T == UInt64) +@inlinable +func arrayOfBytes(value: T, length totalBytes: Int = MemoryLayout.size) -> Array { + let valuePointer = UnsafeMutablePointer.allocate(capacity: 1) + valuePointer.pointee = value + + let bytesPointer = UnsafeMutablePointer(OpaquePointer(valuePointer)) + var bytes = Array(repeating: 0, count: totalBytes) + for j in 0...size, totalBytes) { + bytes[totalBytes - 1 - j] = (bytesPointer + j).pointee + } + + valuePointer.deinitialize(count: 1) + valuePointer.deallocate() + + return bytes +} From 5df7be7335855e36df46ff93d29bcf2ee9a3f923 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 18 Jun 2022 18:52:51 +0530 Subject: [PATCH 21/52] Changed bitString to ecBits for accurate encodings --- Sources/LibP2PCrypto/PEM/ASN1/ASN1Decoder.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/LibP2PCrypto/PEM/ASN1/ASN1Decoder.swift b/Sources/LibP2PCrypto/PEM/ASN1/ASN1Decoder.swift index 890b469..86f0221 100644 --- a/Sources/LibP2PCrypto/PEM/ASN1/ASN1Decoder.swift +++ b/Sources/LibP2PCrypto/PEM/ASN1/ASN1Decoder.swift @@ -91,6 +91,7 @@ extension ASN1 { let length = try scanner.consumeLength() let data = try scanner.consume(length: length) //print("Found an EC Curve Obj ID: [\(data.map { "\($0)" }.joined(separator: ","))]") + //return .ecObject(data: data) return .objectIdentifier(data: data) } @@ -104,7 +105,8 @@ extension ASN1 { let data = try scanner.consume(length: length - 1) //print("Found an EC Curve Bit String: [\(data.map { "\($0)" }.joined(separator: ","))]") - return .bitString(data: data) + //return .bitString(data: data) + return .ecBits(data: data) } throw DecodingError.invalidType(value: firstByte) From a326ad99f4ab4e1f255a5f58d37609715309892a Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 18 Jun 2022 18:53:48 +0530 Subject: [PATCH 22/52] Added PEM exports to our KeyPair struct --- Sources/LibP2PCrypto/Keys/KeyPair.swift | 38 +++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Sources/LibP2PCrypto/Keys/KeyPair.swift b/Sources/LibP2PCrypto/Keys/KeyPair.swift index ae5c200..3fc4e7b 100644 --- a/Sources/LibP2PCrypto/Keys/KeyPair.swift +++ b/Sources/LibP2PCrypto/Keys/KeyPair.swift @@ -332,3 +332,41 @@ extension LibP2PCrypto.Keys.KeyPair { } } } + +extension LibP2PCrypto.Keys.KeyPair { + + func exportPublicPEM(withHeaderAndFooter:Bool = true) throws -> Array { + //guard let der = publicKey as? DEREncodable else { throw NSError(domain: "Unknown private key type", code: 0) } + return try publicKey.exportPublicKeyPEM(withHeaderAndFooter: withHeaderAndFooter) + } + + func exportPrivatePEM(withHeaderAndFooter:Bool = true) throws -> Array { + guard let privKey = self.privateKey else { throw NSError(domain: "No private key available to export", code: 0) } + //guard let der = privKey as? DEREncodable else { throw NSError(domain: "Unknown private key type", code: 0) } + return try privKey.exportPrivateKeyPEM(withHeaderAndFooter: withHeaderAndFooter) + } + + func exportPublicPEMString(withHeaderAndFooter:Bool = true) throws -> String { + //guard let der = publicKey as? DEREncodable else { throw NSError(domain: "Unknown private key type", code: 0) } + return try publicKey.exportPublicKeyPEMString(withHeaderAndFooter: withHeaderAndFooter) + } + + func exportPrivatePEMString(withHeaderAndFooter:Bool = true) throws -> String { + guard let privKey = self.privateKey else { throw NSError(domain: "No private key available to export", code: 0) } + //guard let der = privKey as? DEREncodable else { throw NSError(domain: "Unknown private key type", code: 0) } + return try privKey.exportPrivateKeyPEMString(withHeaderAndFooter: withHeaderAndFooter) + } + + func exportEncryptedPrivatePEM(withPassword password:String, usingPBKDF pbkdf:PEM.PBKDFAlgorithm? = nil, andCipher cipher:PEM.CipherAlgorithm? = nil) throws -> Array { + let cipher = try cipher ?? .aes_128_cbc(iv: LibP2PCrypto.randomBytes(length: 16)) + let pbkdf = try pbkdf ?? .pbkdf2(salt: LibP2PCrypto.randomBytes(length: 8), iterations: 2048) + + return try PEM.encryptPEM(Data(self.privateKey!.exportPrivateKeyPEMRaw()), withPassword: password, usingPBKDF: pbkdf, andCipher: cipher).bytes + } + + func exportEncryptedPrivatePEMString(withPassword password:String, usingPBKDF pbkdf:PEM.PBKDFAlgorithm? = nil, andCipher cipher:PEM.CipherAlgorithm? = nil) throws -> String { + let data = try self.exportEncryptedPrivatePEM(withPassword: password, usingPBKDF: pbkdf, andCipher: cipher) + return String(data: Data(data), encoding: .utf8)! + } + +} From e355239c499ec4e3af3fffca774dd3548b23d3cb Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 18 Jun 2022 18:54:33 +0530 Subject: [PATCH 23/52] Added DERCodable conformance to our CommonPublicKey and CommonPrivateKey --- Sources/LibP2PCrypto/Keys/CommonPrivateKey.swift | 2 +- Sources/LibP2PCrypto/Keys/CommonPublicKey.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/LibP2PCrypto/Keys/CommonPrivateKey.swift b/Sources/LibP2PCrypto/Keys/CommonPrivateKey.swift index d020ca3..424df9c 100644 --- a/Sources/LibP2PCrypto/Keys/CommonPrivateKey.swift +++ b/Sources/LibP2PCrypto/Keys/CommonPrivateKey.swift @@ -8,7 +8,7 @@ import Foundation import Multibase -public protocol CommonPrivateKey { +public protocol CommonPrivateKey:DERCodable { static var keyType:LibP2PCrypto.Keys.GenericKeyType { get } /// Init from raw representation diff --git a/Sources/LibP2PCrypto/Keys/CommonPublicKey.swift b/Sources/LibP2PCrypto/Keys/CommonPublicKey.swift index 9eb96ef..6d5045d 100644 --- a/Sources/LibP2PCrypto/Keys/CommonPublicKey.swift +++ b/Sources/LibP2PCrypto/Keys/CommonPublicKey.swift @@ -9,7 +9,7 @@ import Foundation import Multihash import Multibase -public protocol CommonPublicKey { +public protocol CommonPublicKey:DERCodable { static var keyType:LibP2PCrypto.Keys.GenericKeyType { get } /// Init from raw representation From 77f43edf02b409201cc1c336f7fdf22613e96adf Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 18 Jun 2022 18:55:13 +0530 Subject: [PATCH 24/52] PEM import, export and encrypted private key tests. --- .../LibP2PCryptoTests/LibP2PCryptoTests.swift | 289 +++++++++++++++++- 1 file changed, 286 insertions(+), 3 deletions(-) diff --git a/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift b/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift index 1bdf6e0..8ddb246 100644 --- a/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift +++ b/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift @@ -636,8 +636,27 @@ final class libp2p_cryptoTests: XCTestCase { XCTAssert(keyPair.keyType == .rsa) XCTAssertEqual(keyPair.attributes()?.size, 1024) XCTAssertNil(keyPair.privateKey) + + XCTAssertEqual(try keyPair.exportPublicPEMString(), pem) } + + func testPemParsing_RSA_1024_Private() throws { + + let pem = TestPEMKeys.RSA_1024_PRIVATE + //let keyPair = try LibP2PCrypto.Keys.parsePem(pem) + let keyPair = try LibP2PCrypto.Keys.KeyPair(pem: pem) + + print(keyPair) + print(keyPair.attributes() ?? "NIL") + + XCTAssert(keyPair.keyType == .rsa) + XCTAssertEqual(keyPair.attributes()?.size, 1024) + XCTAssertNotNil(keyPair.privateKey) + + XCTAssertEqual(try keyPair.exportPrivatePEMString(), pem) + } + func testPemParsing_RSA_1024_Public_2() throws { let pem = """ -----BEGIN RSA PUBLIC KEY----- @@ -830,6 +849,8 @@ final class libp2p_cryptoTests: XCTestCase { print(keyPair) XCTAssert(keyPair.keyType == .ed25519) XCTAssertNil(keyPair.privateKey) + + XCTAssertEqual(try keyPair.exportPublicPEMString(), pem) } @@ -890,9 +911,10 @@ final class libp2p_cryptoTests: XCTestCase { XCTAssert(keyPair.keyType == .ed25519) XCTAssertNotNil(keyPair.privateKey) XCTAssertEqual(keyPair.publicKey.asString(base: .base64Pad), "CM3Nzttt7KmXG9qDEYys++oQ9G749jqrbRRs92BUzpA=") + + XCTAssertEqual(try keyPair.exportPrivatePEMString(), pem) } - func testSecp256k1PemImport_Public_Manual() throws { let pem = """ -----BEGIN PUBLIC KEY----- @@ -941,8 +963,10 @@ final class libp2p_cryptoTests: XCTestCase { XCTAssert(keyPair.keyType == .secp256k1) XCTAssertNil(keyPair.privateKey) print(keyPair.attributes() ?? "NIL") + + XCTAssertEqual(try keyPair.exportPublicPEMString(), pem) } - + func testSecp256k1PemImport_Private_Manual() throws { let pem = """ -----BEGIN EC PRIVATE KEY----- @@ -987,7 +1011,7 @@ final class libp2p_cryptoTests: XCTestCase { X7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== -----END EC PRIVATE KEY----- """ - + let keyPair = try LibP2PCrypto.Keys.KeyPair(pem: pem) print(keyPair) @@ -996,6 +1020,49 @@ final class libp2p_cryptoTests: XCTestCase { XCTAssertEqual(keyPair.privateKey?.rawRepresentation.asString(base: .base64Pad), "mZunAPeZmGUS2IbOaCuikn+dJ7BzxQ/IET3CJvvjaxo=") /// Assert that we can derive the public from the private key XCTAssertEqual(keyPair.publicKey.asString(base: .base64Pad), "IgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w==") + + print(try keyPair.exportPrivatePEM().asString(base: .base16)) + + XCTAssertEqual(try keyPair.exportPrivatePEMString(), pem) + } + + func testTempSecp() throws { + let pemOG = """ + -----BEGIN EC PRIVATE KEY----- + MHQCAQEEIJmbpwD3mZhlEtiGzmgropJ/nSewc8UPyBE9wib742saoAcGBSuBBAAK + oUQDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwf + X7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== + -----END EC PRIVATE KEY----- + """ + /// Sequence: + /// Integer: 01 + /// OctetString: 999ba700f799986512d886ce682ba2927f9d27b073c50fc8113dc226fbe36b1a + /// ObjectID: 06052b8104000a + /// BitString: 4200042200beb1c3052d405d7773a5328769e926c46811ab1f2cf0c437af8ec6d4d603a1763bbe15065a00bc1f5fb5e6b0784a145358a554b419784c333cc57f52ddef + + let pemRECON = """ + -----BEGIN EC PRIVATE KEY----- + MHQCAQEEIJmbpwD3mZhlEtiGzmgropJ/nSewc8UPyBE9wib742saoAcGBSuBBAAK + oUQAQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwf + X7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== + -----END EC PRIVATE KEY----- + """ + /// Sequence: + /// Integer: 01 + /// OctetString: 999ba700f799986512d886ce682ba2927f9d27b073c50fc8113dc226fbe36b1a + /// ObjectID: 06052b8104000a + /// BitString: 4200042200beb1c3052d405d7773a5328769e926c46811ab1f2cf0c437af8ec6d4d603a1763bbe15065a00bc1f5fb5e6b0784a145358a554b419784c333cc57f52ddef + + + let chunks = pemOG.bytes.split(separator: 0x0a) + let base64 = String(data: Data(chunks[1.. Date: Sun, 19 Jun 2022 00:57:44 +0530 Subject: [PATCH 25/52] Removed old files and directories --- .../Utils/ASN1_OLD/ASN1Parser.swift | 700 ------------------ .../Utils/ASN1_OLD/PEM+DER/DER_OLD.swift | 126 ---- .../Utils/ASN1_OLD/PEM+DER/PEM_OLD.swift | 525 ------------- 3 files changed, 1351 deletions(-) delete mode 100644 Sources/LibP2PCrypto/Utils/ASN1_OLD/ASN1Parser.swift delete mode 100644 Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/DER_OLD.swift delete mode 100644 Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/PEM_OLD.swift diff --git a/Sources/LibP2PCrypto/Utils/ASN1_OLD/ASN1Parser.swift b/Sources/LibP2PCrypto/Utils/ASN1_OLD/ASN1Parser.swift deleted file mode 100644 index 4bfb8a1..0000000 --- a/Sources/LibP2PCrypto/Utils/ASN1_OLD/ASN1Parser.swift +++ /dev/null @@ -1,700 +0,0 @@ -//// -//// Asn1Parser.swift -//// SwiftyRSA -//// -//// Created by Lois Di Qual on 5/9/17. -//// Copyright © 2017 Scoop. All rights reserved. -//// Modified by Brandon Toms on 5/1/22 -//// -// -//import Foundation -//import Multibase -// -///// Object Identifiers -///// [6,8,42,134,72,206,61,3,1,7] -> EC Curve 256 ':prime256v1' -///// [6,5,43,129,4,0,34] -> EC Curve 384 'secp384r1' -///// [6,5,43,129,4,0,35] -> EC Curve 521 ':secp521r1' -///// [42,134,72,206,61,2,1] -> EC Pub ':id-ecPublicKey' -///// [42,134,72,206,61,3,1,7] -> EC Pub 256 ':prime256v1' -///// [43,129,4,0,34] -> EC Pub 384 ':secp384r1' -///// [43,129,4,0,35] -> EC Pub 521 ':secp521r1' -///// [6,5,43,129,4,0,10] -> EC Secp256k1 Private -// -///// 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.. 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.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:CustomStringConvertible { -// case sequence(nodes: [Node]) -// case integer(data: Data) -// case objectIdentifier(data: Data) -// case null -// case bitString(data: Data) -// case octetString(data: Data) -// -// var description: String { -// printNode(self, level: 0) -// } -// } -// -// 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 -// -//// print([firstByte].asString(base: .base16)) -// -// // 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) -// //print(Int(data.asString(base: .base16), radix: 16) ?? -1) -// return .integer(data: data) -// } -// -// // Object identifier -// if firstByte == 0x06 { -// let length = try scanner.consumeLength() -// let data = try scanner.consume(length: length) -// //print(String(data: data, encoding: .ascii)) -// //print("Object ID: [\(data.map { "\($0)" }.joined(separator: ","))]") -// 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) -//// print(data.asString(base: .base64)) -//// print() -//// print(data.bytes) -//// print() -// 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 -// } -//} -// -// -//private let Mappings:[Array:String] = [ -// [6,8,42,134,72,206,61,3,1,7]: "prime256v1", -// [6,5,43,129,4,0,34]: "secp384r1", -// [6,5,43,129,4,0,35]: "secp521r1", -// [42,134,72,206,61,2,1]: "id-ecPublicKey", -// [42,134,72,206,61,3,1,7]: "prime256v1", -// [43,129,4,0,34]: "secp384r1", -// [43,129,4,0,35]: "secp521r1", -// [6,5,43,129,4,0,10]: "secp256k1", -// [43,101,112]: "Ed25519", -// [42,134,72,134,247,13,1,1,1]: "rsaEncryption" -//] -// -///// 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 Asn1ParserECPrivate { -// -// enum ObjectIdentifier:CustomStringConvertible { -// case prime256v1 -// case secp384r1 -// case secp521r1 -// case id_ecPublicKey -// case secp256k1 -// case Ed25519 -// case rsaEncryption -// /// Encryption Tags and Ciphers -// case aes_128_cbc // The cipher used to encrypt an encrypted key // des_ede3_cbc -// case PBKDF2 //An Encrypted PEM Key that uses PBKDF2 to derive a the AES key -// case PBES2 //An Encrypted PEM Key -// case unknown(Data) -// -// init(data:Data) { -// /// Often times Object Identifiers in private keys begin with an additional 6,5 or 6,8. -// /// If the objID has this prefix, we drop the first two bytes before attempting to classify... -// let d = data.first == 6 ? data.dropFirst(2) : data -// switch d.bytes { -// case [42,134,72,206,61,2,1]: -// self = .id_ecPublicKey -// -// case [42,134,72,206,61,3,1,7]: -// self = .prime256v1 -// -// case [43,129,4,0,34]: -// self = .secp384r1 -// -// case [43,129,4,0,35]: -// self = .secp521r1 -// -// case [43,129,4,0,10]: -// self = .secp256k1 -// -// case [43,101,112]: -// self = .Ed25519 -// -// case [42,134,72,134,247,13,1,1,1]: -// self = .rsaEncryption -// -// case [96,134,72,1,101,3,4,1,2]: -// self = .aes_128_cbc -// -// case [42,134,72,134,247,13,1,5,12]: -// self = .PBKDF2 -// -// case [42,134,72,134,247,13,1,5,13]: -// self = .PBES2 -// -// default: -// print("Found an unknown Obj ID: [\(data.map { "\($0)" }.joined(separator: ","))]") -// self = .unknown(data) -// } -// } -// -// var keyType:KeyType? { -// switch self { -// case .secp256k1: -// return .secp256K1 -// case .Ed25519: -// return .ed25519 -// case .rsaEncryption: -// return .rsa -// default: //Generic EC Curves aren't supported yet... -// return nil -// } -// } -// -// var description:String { -// switch self { -// case .prime256v1: return "prime256v1" -// case .secp384r1: return "secp384r1" -// case .secp521r1: return "secp521r1" -// case .id_ecPublicKey: return "id_ecPublicKey" -// case .secp256k1: return "secp256k1" -// case .Ed25519: return "Ed25519" -// case .rsaEncryption: return "rsaEncryption" -// /// Encryption Tags and Ciphers.... -// case .PBES2: return "PBES2" -// case .PBKDF2: return "PBKDF2" -// case .aes_128_cbc: return "aes_128_cbc" -// case .unknown(let data): -// return "Unknown Obj ID: [\(data.map { "\($0)" }.joined(separator: ","))]" -// } -// } -// } -// -// /// An ASN1 node -// enum Node { -// case sequence(nodes: [Node]) -// case integer(data: Data) -// case objectIdentifier(data: ObjectIdentifier) -// 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: 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) -// } -// -// // EC Curves Cont 0 identifier (obj id) -// if firstByte == 0xa0 { -// let length = try scanner.consumeLength() -// let data = try scanner.consume(length: length) -// //print("Found an EC Curve Obj ID: [\(data.map { "\($0)" }.joined(separator: ","))]") -// return .objectIdentifier(data: ObjectIdentifier(data: data)) -// } -// -// // EC Curves Cont 1 identifier (bit string) -// if firstByte == 0xa1 { -// 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) -// //print("Found an EC Curve Bit String: [\(data.map { "\($0)" }.joined(separator: ","))]") -// return .bitString(data: data) -// } -// -// print("Unknown byte: \([firstByte].asString(base: .base16))") -// -// 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] = [] -// do { -// while !scanner.isComplete { -// let node = try parseNode(scanner: scanner) -// nodes.append(node) -// } -// } catch { -// return nodes -// } -// return nodes -// } -//} -// -//extension LibP2PCrypto.Keys { -// -// // 256 objId -> 2a8648ce3d0301 -// // 384 objId -> 2a8648ce3d0201 -// // 521 objId -> 2a8648ce3d0201 -// public struct ASN1Parts { -// let isPrivateKey:Bool -// let keyBits:Data -// let objectIdentifier:Data -// } -// -// public static func parseASN1(pemData:Data) throws -> ASN1Parts { -// let asn = try Asn1Parser.parse(data: pemData) -// -// var bitString:Data? = nil -// var objId:Data? = nil -// var isPrivate:Bool = false -// if case .sequence(let nodes) = asn { -// nodes.forEach { -// switch $0 { -// case .objectIdentifier(let data): -// if data.first == 0x2a { -// //print("Got our obj id: \(data.asString(base: .base64))") -// objId = data -// } -// case .bitString(let data): -// //print("Got our bit string: \(data.asString(base: .base64))") -// bitString = data -// case .sequence(let nodes): -// nodes.forEach { n in -// switch n { -// case .objectIdentifier(let data): -// if data.first == 0x2a { -// //print("Got our obj id: \(data.asString(base: .base64))") -// objId = data -// } -// case .bitString(let data): -// //print("Got our bit string: \(data.asString(base: .base64))") -// bitString = data -// case .octetString(let data): -// //Private Keys trigger -// bitString = data -// isPrivate = true -// default: -// return -// } -// } -// case .octetString(let data): -// //Private Keys trigger -// bitString = data -// isPrivate = true -// default: -// return -// } -// } -// } -// -// guard let id = objId, let bits = bitString else { -// throw NSError(domain: "Unsupported asn1 format", code: 0, userInfo: nil) -// } -// -// return ASN1Parts(isPrivateKey: isPrivate, keyBits: bits, objectIdentifier: id) -// -// } -// -// public static func parseASN1ECPrivate(pemData:Data) throws -> Data { -// let asn = try Asn1ParserECPrivate.parse(data: pemData) -// -// var octetString:Data? = nil -// if case .sequence(let nodes) = asn { -// nodes.forEach { -// switch $0 { -// case .sequence(let nodes): -// nodes.forEach { n in -// switch n { -// case .octetString(let data): -// octetString = data -// default: -// return -// } -// } -// case .octetString(let data): -// octetString = data -// default: -// return -// } -// } -// } else if case .octetString(let data) = asn { -// octetString = data -// } -// -// guard let bits = octetString else { -// throw NSError(domain: "Unsupported asn1 format", code: 0, userInfo: nil) -// } -// -// return bits -// } -// -// /// 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 -// public static func stripX509HeaderFromDER(keyData: Data) throws -> Data { -// -// let node: Asn1Parser.Node -// do { -// node = try Asn1Parser.parse(data: keyData) -// } catch { -// throw NSError(domain: "asn1ParsingFailed", code: 0, userInfo: nil) -// } -// -// // Ensure the raw data is an ASN1 sequence -// guard case .sequence(let nodes) = node else { -// throw NSError(domain: "invalidAsn1RootNode", code: 0, userInfo: nil) -// } -// -// // 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 NSError(domain: "invalidAsn1Structure", code: 0, userInfo: nil) -// } -//} -// -//enum ASN1Encoder { -// private static func asn1LengthPrefix(_ bytes:[UInt8]) -> [UInt8] { -// if bytes.count >= 0x80 { -// var lengthAsBytes = withUnsafeBytes(of: bytes.count.bigEndian, Array.init) -// while lengthAsBytes.first == 0 { lengthAsBytes.removeFirst() } -// return [(0x80 + UInt8(lengthAsBytes.count))] + lengthAsBytes -// } else { -// return [UInt8(bytes.count)] -// } -// } -// -// private static func asn1LengthPrefixed(_ bytes:[UInt8]) -> [UInt8] { -// asn1LengthPrefix(bytes) + bytes -// } -// -// public static func encode(_ node:Asn1Parser.Node) -> [UInt8] { -// switch node { -// case .integer(let integer): -// return [0x02] + asn1LengthPrefixed(integer.bytes) -// case .bitString(let bits): -// return [0x03] + asn1LengthPrefixed([0x00] + bits.bytes) -// case .octetString(let octet): -// return [0x04] + asn1LengthPrefixed(octet.bytes) -// case .null: -// return [0x05, 0x00] -// case .objectIdentifier(let oid): -// return [0x06] + asn1LengthPrefixed(oid.bytes) -// case .sequence(let nodes): -// return [0x30] + asn1LengthPrefixed( nodes.reduce(into: Array(), { partialResult, node in -// partialResult += encode(node) -// }) ) -// } -// } -//} -// -//fileprivate func printNode(_ node:Asn1Parser.Node, level:Int) -> String { -// var str:[String] = [] -// let prefix = String(repeating: "\t", count: level) -// switch node { -// case .integer(let int): -// str.append("\(prefix)Integer: \(int.asString(base: .base16))") -// case .bitString(let bs): -// str.append("\(prefix)BitString: \(bs.asString(base: .base16))") -// case .null: -// str.append("\(prefix)NULL") -// case .objectIdentifier(let oid): -// str.append("\(prefix)ObjectID: \(oid.asString(base: .base16))") -// case .octetString(let os): -// str.append("\(prefix)OctetString: \(os.asString(base: .base16))") -// case .sequence(let nodes): -// nodes.forEach { str.append(printNode($0, level: level + 1)) } -// } -// return str.joined(separator: "\n") -//} diff --git a/Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/DER_OLD.swift b/Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/DER_OLD.swift deleted file mode 100644 index 580393f..0000000 --- a/Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/DER_OLD.swift +++ /dev/null @@ -1,126 +0,0 @@ -//// -//// File.swift -//// -//// -//// Created by Brandon Toms on 5/22/22. -//// -// -//import Foundation -//import Multibase -// -//extension LibP2PCrypto.Keys { -// /// Expects a PEM Public Key with the x509 header information included (object identifier) -// /// -// /// - Note: Handles RSA and EC Public Keys -// public static func importPublicDER(_ der:String) throws -> KeyPair { -// let chunks = der.split(separator: "\n") -// guard chunks.count > 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN RSA PUBLIC"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid DER Format", code: 0, userInfo: nil) -// } -// -// let raw = try BaseEncoding.decode(chunks[1.. KeyPair { -// let chunks = der.split(separator: "\n") -// guard chunks.count > 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN RSA PRIVATE"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid DER Format", code: 0, userInfo: nil) -// } -// -// var raw = try BaseEncoding.decode(chunks[1.. PrivKey { -//// -//// let chunks = der.split(separator: "\n") -//// guard chunks.count > 3, -//// let f = chunks.first, f.hasPrefix("-----BEGIN"), -//// let l = chunks.last, l.hasSuffix("-----") else { -//// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -//// } -//// -//// let raw = try BaseEncoding.decode(chunks[1..? -//// //let privKey = SecKeyCreateWithData(d as CFData, attributes as CFDictionary, &error) -//// let privKey = SecKeyCreateFromData([:] as CFDictionary, d as CFData, &error) -//// -//// guard let key = privKey else { -//// -//// throw NSError(domain: "Failed to gen priv key... \(error.debugDescription)", code: 0, userInfo: nil) -//// } -//// -//// if let pubkey = try? key.extractPubKey() { -//// print("Got the pub key...") -//// print((try? pubkey.asString(base: .base16)) ?? "nil") -//// } -//// -//// print(key.attributes) -//// -//// print((try? key.rawRepresentation()) ?? "Failed to get raw rep...") -//// -//// return key -//// -//// //return try LibP2PCrypto.Keys.secKeyFrom(data: d, isPrivateKey: true, keyType: .EC(curve: .P256)) -//// } -// -// /// Appends PEM Header and Footer -// /// Base64 encodes DER PubKey -// /// MacOS -> Use -// /// iOS roll our own -// /// https://github.com/ibm-cloud-security/Swift-JWK-to-PEM -// /// https://github.com/Kitura/OpenSSL -//// private func toDER(keyPair:LibP2PCrypto.Keys.KeyPair) throws -> String { -//// -//// // 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 keyData = try keyPair.publicKey.rawRepresentation() -//// let chunks = keyData.base64EncodedString().split(intoChunksOfLength: 64) -//// -//// let pem = [ -//// "-----BEGIN \(keyPair.keyType.name)-----", -//// chunks.joined(separator: "\n"), -//// "-----END \(keyPair.keyType.name)-----" -//// ] -//// -//// return pem.joined(separator: "\n") -//// } -// -// -//} diff --git a/Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/PEM_OLD.swift b/Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/PEM_OLD.swift deleted file mode 100644 index 8bb8e30..0000000 --- a/Sources/LibP2PCrypto/Utils/ASN1_OLD/PEM+DER/PEM_OLD.swift +++ /dev/null @@ -1,525 +0,0 @@ -//// -//// PEM.swift -//// -//// -//// Created by Brandon Toms on 5/22/22. -//// - -//import Foundation -//import Multibase -//import Crypto - -//extension LibP2PCrypto.Keys { -// public struct ParsedPem { -// let isPrivate:Bool -// let type:KeyPairType -// let rawKey:Data -// } -// -// /// Parse the pem file into ASN1 bits... -// /// Scan the bits for Object Identifiers and classify the key type -// /// Based on the key type... scan the bits for the key data -// /// Return a ParsedPem struct that we can use to instantiate any of our supported KeyPairTypes... -// public static func parsePem(_ pem:String) throws -> KeyPair { -// let chunks = pem.split(separator: "\n") -// guard chunks.count >= 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } -// -// /// If its a DER re route it... -// if f.contains("-----BEGIN RSA PUBLIC") { return try LibP2PCrypto.Keys.importPublicDER(pem) } -// else if f.contains("-----BEGIN RSA PRIVATE") { return try LibP2PCrypto.Keys.importPrivateDER(pem) } -// -// let isPrivate:Bool = f.contains("PRIVATE") -// -// let rawPem = try BaseEncoding.decode(chunks[1.. KeyPair { -// var type:KeyPairType? = nil -// let asn = try Asn1ParserECPrivate.parse(data: rawPem) -// -// print("ASN1 Nodes") -// print(asn) -// print("----------") -// -// guard case .sequence(let nodes) = asn else { throw NSError(domain: "Failed to parse PEM", code: 0, userInfo: nil) } -// let ids = objIdsInSequence(nodes) -// -// if ids.contains(where: { (id) -> Bool in -// if case .rsaEncryption = id { return true } else { return false } -// }) { -// type = .RSA(bits: .B1024) //Bit length doesn't matter here, we're just broadly classifying it... -// } else if ids.contains(where: { (id) -> Bool in -// if case .secp256k1 = id { return true } else { return false } -// }) { -// type = .Secp256k1 -// } else if ids.contains(where: { (id) -> Bool in -// if case .Ed25519 = id { return true } else { return false } -// }) { -// type = .Ed25519 -// } else if ids.contains(where: { (id) -> Bool in -// switch id { -// case .prime256v1, .secp384r1, .secp521r1: return true -// default: return false -// } -// }) { -// throw NSError(domain: "No EC Key Support Yet", code: 0, userInfo: nil) -// //type = .EC(curve: .P256) //Curve bits dont matter here, we're just broadly classifying it... -// } -// -// guard let keyType = type else { throw NSError(domain: "Failed to classify key", code: 0, userInfo: nil) } -// -// guard case .sequence(let top) = asn else { -// throw NSError(domain: "Failed to parse Asn1", code: 0, userInfo: nil) -// } -// -// var rawKeyData:Data? = nil -// -// if isPrivate { -// // First Octet -// guard let octet = octetsInSequence(top).first else { -// throw NSError(domain: "Failed to extract \(keyType.name) \(isPrivate ? "Private" : "Public") key", code: 0, userInfo: nil) -// } -// rawKeyData = octet -// } else { -// // First Bit String... -// guard let bitString = bitStringsInSequence(top).first else { -// throw NSError(domain: "Failed to extract \(keyType.name) \(isPrivate ? "Private" : "Public") key", code: 0, userInfo: nil) -// } -// rawKeyData = bitString -// } -// -// // ED25519 Private Keys are wrapped in an additional octetString node, lets remove it... -// if isPrivate, case .Ed25519 = keyType, rawKeyData?.count == 34 { -// rawKeyData?.removeFirst(2) -// } -// -// guard let keyData = rawKeyData else { -// throw NSError(domain: "Failed to extract key data from asn1 nodes", code: 0, userInfo: nil) -// } -// -// //return ParsedPem(isPrivate: isPrivate, type: keyType, rawKey: keyData) -// -// // At this point we know if its a public or private key, the type of key, and the raw bits of the key. -// // We can instantiate the key, ensure it's valid, then create a return a PublicKey or PrivateKey -// switch keyType { -// case .RSA: -// if isPrivate { -// return try KeyPair(privateKey: RSAPrivateKey(rawRepresentation: keyData)) -// } else { -// return try KeyPair(publicKey: RSAPublicKey(rawRepresentation: keyData)) -// } -// case .Ed25519: -// if isPrivate { -// return try KeyPair(privateKey: Curve25519.Signing.PrivateKey(rawRepresentation: keyData)) -// } else { -// return try KeyPair(publicKey: Curve25519.Signing.PublicKey(rawRepresentation: keyData)) -// } -// case .Secp256k1: -// if isPrivate { -// return try KeyPair(privateKey: Secp256k1PrivateKey(keyData.bytes)) -// } else { -// return try KeyPair(publicKey: Secp256k1PublicKey(keyData.bytes)) -// } -// //default: -// /// - TODO: Internal Support For EC Keys (without support for marshaling) -// // throw NSError(domain: "Unsupported Key Type \(keyType.description)", code: 0, userInfo: nil) -// } -// } -//} -// -// /// Importes an Encrypted PEM Key File -// /// -// /// An ASN1 Node Tree of an Encrypted RSA PEM Key (PBKDF2 and AES_CBC_128) -// /// ``` -// /// sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //[42,134,72,134,247,13,1,5,13] -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //PBKDF2 //[42,134,72,134,247,13,1,5,12] -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 8 bytes), //SALT -// /// libp2p_crypto.Asn1Parser.Node.integer(data: 2 bytes) //ITTERATIONS -// /// ]) -// /// ]), -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //des-ede3-cbc [96,134,72,1,101,3,4,1,2] -// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 16 bytes) //IV -// /// ]) -// /// ]) -// /// ]), -// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 640 bytes) -// /// ]) -// /// ``` -// static func parseEncryptedPem(_ pem:String, password:String) throws -> KeyPair { -// let chunks = pem.split(separator: "\n") -// guard chunks.count >= 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN ENCRYPTED"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid Encrypted PEM Format", code: 0, userInfo: nil) -// } -// -// let isPrivate:Bool = f.contains("PRIVATE") -// -// let rawPem = try BaseEncoding.decode(chunks[1.. 100 { -// ciphertextData = $0 -// } else { -// saltData = $0 -// } -// } -// -// /// There should be only one integer, the itteration count... -// itterationsData = integersInSequence(nodes).first -// -// guard let salt = saltData, let iv = ivData, let itterations = itterationsData, let ciphertext = ciphertextData else { -// throw NSError(domain: "Failed to parse our pcks#8 key", code: 0, userInfo: nil) -// } -// -// // Attempt to derive the aes encryption key from the password and salt -// // PBKDF2-SHA1 -// guard let key = PBKDF2.SHA1(password: password, salt: salt, keyByteCount: iv.count, rounds: itterations) else { -// throw NSError(domain: "Failed to derive key from password and salt", code: 0, userInfo: nil) -// } -// -// //print("Key 1 -> \(key.asString(base: .base16))") -// -// //Create our CBC AES Cipher -// let aes = try LibP2PCrypto.AES.createKey(key: key, iv: iv) -// //let aes = try AES(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: .noPadding) -// -// // GCM Doesn't work on OPENSSL Encrypted PEM Files but I saw mention of it in libp2p-crypto-js so perhaps we'll need it later... -// //let aes = try AES(key: key.bytes, blockMode: GCM(iv: iv.bytes, mode: .detached), padding: .noPadding) -// -// let decryptedKey = try aes.decrypt(ciphertext.bytes) -// -// // At this point we have regular unencrypted PEM data rep of a key, lets parse it... -// return try self.parsePem(decryptedKey, isPrivate: isPrivate) -// } -// -// /// Traverses a Node tree and returns all instances of integers -// private static func integersInSequence(_ nodes:[Asn1ParserECPrivate.Node]) -> [Int] { -// var integers:[Int?] = [] -// -// nodes.forEach { -// if case .integer(let data) = $0 { integers.append(Int(data.asString(base: .base16), radix: 16)) } -// else if case .sequence(let nodes) = $0 { -// return integers.append(contentsOf: integersInSequence(nodes) ) -// } -// } -// -// return integers.compactMap { $0 } -// } -// -// /// Traverses a Node tree and returns all instances of bitStrings -// private static func bitStringsInSequence(_ nodes:[Asn1ParserECPrivate.Node]) -> [Data] { -// var bitString:[Data] = [] -// -// nodes.forEach { -// if case .bitString(let data) = $0 { bitString.append(data) } -// else if case .sequence(let nodes) = $0 { -// return bitString.append(contentsOf: bitStringsInSequence(nodes) ) -// } -// } -// -// return bitString -// } -// -// /// Traverses a Node tree and returns all instances of bitStrings -// private static func octetsInSequence(_ nodes:[Asn1ParserECPrivate.Node]) -> [Data] { -// var octets:[Data] = [] -// -// nodes.forEach { -// if case .octetString(let data) = $0 { octets.append(data) } -// else if case .sequence(let nodes) = $0 { -// return octets.append(contentsOf: octetsInSequence(nodes) ) -// } -// } -// -// return octets -// } -// -// /// Traverses a Node tree and returns all instances of objectIds -// private static func objIdsInSequence(_ nodes:[Asn1ParserECPrivate.Node]) -> [Asn1ParserECPrivate.ObjectIdentifier] { -// var objs:[Asn1ParserECPrivate.ObjectIdentifier] = [] -// -// nodes.forEach { -// if case .objectIdentifier(let id) = $0 { objs.append(id) } -// else if case .sequence(let nodes) = $0 { -// return objs.append(contentsOf: objIdsInSequence(nodes) ) -// } -// } -// -// return objs -// } -// -// /// Expects a PEM Public Key with the x509 header information included (object identifier) -// /// -// /// - Note: Handles RSA Public Keys -// public static func importPublicPem(_ pem:String) throws -> CommonPublicKey { -// let chunks = pem.split(separator: "\n") -// guard chunks.count > 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } -// -// let raw = try BaseEncoding.decode(chunks[1.. Data { -//// let chunks = pem.split(separator: "\n") -//// guard chunks.count > 3, -//// let f = chunks.first, f.hasPrefix("-----BEGIN"), -//// let l = chunks.last, l.hasSuffix("-----") else { -//// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -//// } -//// -//// //print("Attempting to decode: \(chunks[1.. CommonPrivateKey { -// let chunks = pem.split(separator: "\n") -// guard chunks.count > 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN PRIVATE"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } -// -// //print("Attempting to decode: \(chunks[1.. PrivKey { -//// let chunks = pem.split(separator: "\n") -//// guard chunks.count > 3, -//// let f = chunks.first, f.hasPrefix("-----BEGIN PRIVATE"), -//// let l = chunks.last, l.hasSuffix("-----") else { -//// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -//// } -//// -//// //print("Attempting to decode: \(chunks[1.. PubKey { -//// var pubKey:Data? = nil -//// switch keyType { -//// case .ECDSA(curve: .P256): -//// pubKey = try P256.Signing.PublicKey(pemRepresentation: pem).rawRepresentation -//// case .ECDSA(curve: .P384): -//// pubKey = try P384.Signing.PublicKey(pemRepresentation: pem).rawRepresentation -//// case .ECDSA(curve: .P521): -//// pubKey = try P521.Signing.PublicKey(pemRepresentation: pem).rawRepresentation -//// default: -//// print("Unsupported KeyType") -//// } -//// -//// guard let pubKeyData = pubKey else { -//// throw NSError(domain: "Unable to parse PEM into Public Key", code: 0, userInfo: nil) -//// } -//// -//// let attributes: [String:Any] = [ -//// kSecAttrKeyType as String: keyType.secKey, -//// kSecAttrKeyClass as String: kSecAttrKeyClassPublic, -//// kSecAttrKeySizeInBits as String: keyType.bits, -//// kSecAttrIsPermanent as String: false -//// ] -//// -//// return try LibP2PCrypto.Keys.secKeyFrom(data: pubKeyData, attributes: attributes) -//// } -// -//// public static func initPrivKeyFromPem(_ pem:String, keyType:LibP2PCrypto.Keys.KeyPairType) throws -> PubKey { -//// var pubKey:Data? = nil -//// switch keyType { -//// case .ECDSA(curve: .P256): -//// pubKey = try P256.Signing.PrivateKey(pemRepresentation: pem).rawRepresentation -//// case .ECDSA(curve: .P384): -//// pubKey = try P384.Signing.PrivateKey(pemRepresentation: pem).rawRepresentation -//// case .ECDSA(curve: .P521): -//// pubKey = try P521.Signing.PrivateKey(pemRepresentation: pem).rawRepresentation -//// default: -//// print("Unsupported KeyType") -//// } -//// -//// guard let pubKeyData = pubKey else { -//// throw NSError(domain: "Unable to parse PEM into Private Key", code: 0, userInfo: nil) -//// } -//// -//// let attributes: [String:Any] = [ -//// kSecAttrKeyType as String: keyType.secKey, -//// kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, -//// kSecAttrKeySizeInBits as String: keyType.bits, -//// kSecAttrIsPermanent as String: false -//// ] -//// -//// return try LibP2PCrypto.Keys.secKeyFrom(data: pubKeyData, attributes: attributes) -//// } -// -// -//// public static func importPem(_ str:String) throws -> KeyPair { -//// -//// let pemData = str.data(using: .utf8) -//// -//// } -// -//// public static func fromPEM(_ str:String, keyType:LibP2PCrypto.Keys.KeyPairType) throws -> SecKey { -//// -//// guard str.hasPrefix("-----BEGIN"), str.hasSuffix("-----") else { throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) } -//// let chunks = str.split(separator: "\n") -//// guard chunks.count > 3 else { throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) } -//// //print(chunks) -//// print("Attempting to decode: \(chunks[1..? -////// let key = SecItemImport(raw.data as CFData, nil, nil, nil, .pemArmour, nil, nil, out) -////// print(key) -////// print(out) -//// let attributesRSAPriv: [String:Any] = [ -//// kSecAttrKeyType as String: kSecAttrKeyTypeRSA, -//// kSecAttrKeyClass as String: kSecAttrKeyClassPublic, -//// kSecAttrKeySizeInBits as String: keyType.bits, -//// kSecAttrIsPermanent as String: false -//// ] -//// -//// var error:Unmanaged? = nil -//// guard let secKey = SecKeyCreateWithData(key as CFData, attributesRSAPriv as CFDictionary, &error) else { -//// //guard let secKey = SecKeyCreateFromData(keyType.params! as CFDictionary, key as CFData, &error) else { -//// throw NSError(domain: "Error constructing SecKey from raw key data: \(error.debugDescription)", code: 0, userInfo: nil) -//// } -//// -//// return secKey -//// } -//} From 305e78ce91b9c7eadb9d2dd3cb1cef7d894dbbb0 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sun, 19 Jun 2022 00:58:24 +0530 Subject: [PATCH 26/52] Moved Integer+Bytes into its own file within utils --- Sources/LibP2PCrypto/PEM/PEM.swift | 42 ----------------- .../LibP2PCrypto/Utils/Integer+Bytes.swift | 47 +++++++++++++++++++ 2 files changed, 47 insertions(+), 42 deletions(-) create mode 100644 Sources/LibP2PCrypto/Utils/Integer+Bytes.swift diff --git a/Sources/LibP2PCrypto/PEM/PEM.swift b/Sources/LibP2PCrypto/PEM/PEM.swift index 32f03e9..412bf00 100644 --- a/Sources/LibP2PCrypto/PEM/PEM.swift +++ b/Sources/LibP2PCrypto/PEM/PEM.swift @@ -607,45 +607,3 @@ extension PEM { return try CipherAlgorithm(objID: objID.bytes, iv: initialVector.bytes) } } - - -#if canImport(Darwin) -import Darwin -#elseif canImport(Glibc) -import Glibc -#elseif canImport(ucrt) -import ucrt -#endif - -extension FixedWidthInteger { - @inlinable - func bytes(totalBytes: Int = MemoryLayout.size) -> Array { - arrayOfBytes(value: self.littleEndian, length: totalBytes) - // TODO: adjust bytes order - // var value = self.littleEndian - // return withUnsafeBytes(of: &value, Array.init).reversed() - } -} - -@_specialize(where T == Int) -@_specialize(where T == UInt) -@_specialize(where T == UInt8) -@_specialize(where T == UInt16) -@_specialize(where T == UInt32) -@_specialize(where T == UInt64) -@inlinable -func arrayOfBytes(value: T, length totalBytes: Int = MemoryLayout.size) -> Array { - let valuePointer = UnsafeMutablePointer.allocate(capacity: 1) - valuePointer.pointee = value - - let bytesPointer = UnsafeMutablePointer(OpaquePointer(valuePointer)) - var bytes = Array(repeating: 0, count: totalBytes) - for j in 0...size, totalBytes) { - bytes[totalBytes - 1 - j] = (bytesPointer + j).pointee - } - - valuePointer.deinitialize(count: 1) - valuePointer.deallocate() - - return bytes -} diff --git a/Sources/LibP2PCrypto/Utils/Integer+Bytes.swift b/Sources/LibP2PCrypto/Utils/Integer+Bytes.swift new file mode 100644 index 0000000..3958ee6 --- /dev/null +++ b/Sources/LibP2PCrypto/Utils/Integer+Bytes.swift @@ -0,0 +1,47 @@ +// +// Integer+Bytes.swift +// +// +// CryptoSwift +// + +#if canImport(Darwin) +import Darwin +#elseif canImport(Glibc) +import Glibc +#elseif canImport(ucrt) +import ucrt +#endif + +extension FixedWidthInteger { + @inlinable + func bytes(totalBytes: Int = MemoryLayout.size) -> Array { + arrayOfBytes(value: self.littleEndian, length: totalBytes) + // TODO: adjust bytes order + // var value = self.littleEndian + // return withUnsafeBytes(of: &value, Array.init).reversed() + } +} + +@_specialize(where T == Int) +@_specialize(where T == UInt) +@_specialize(where T == UInt8) +@_specialize(where T == UInt16) +@_specialize(where T == UInt32) +@_specialize(where T == UInt64) +@inlinable +func arrayOfBytes(value: T, length totalBytes: Int = MemoryLayout.size) -> Array { + let valuePointer = UnsafeMutablePointer.allocate(capacity: 1) + valuePointer.pointee = value + + let bytesPointer = UnsafeMutablePointer(OpaquePointer(valuePointer)) + var bytes = Array(repeating: 0, count: totalBytes) + for j in 0...size, totalBytes) { + bytes[totalBytes - 1 - j] = (bytesPointer + j).pointee + } + + valuePointer.deinitialize(count: 1) + valuePointer.deallocate() + + return bytes +} From 463fad399c08553d880a873fd2fa43f5b031dc08 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sun, 19 Jun 2022 01:14:49 +0530 Subject: [PATCH 27/52] Linux & CryptoSwift throws an error instead of returning a partial DER --- Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift index 81fc80d..b5b5535 100644 --- a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift +++ b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift @@ -70,6 +70,7 @@ extension RSAPrivateKey: DERCodable { } public func exportPrivateKeyPEMRaw() throws -> Array { + #if canImport(Security) let privateDER = try self.privateKeyDER() let asnNodes:ASN1.Node = .sequence(nodes: [ .integer(data: Data(hex: "0x00")), @@ -81,6 +82,9 @@ extension RSAPrivateKey: DERCodable { ]) return ASN1.Encoder.encode(asnNodes) + #else + throw NSError(domain: "CryptoSwift doesn't support exporting private keys yet", code: 0) + #endif } public func exportPrivateKeyPEM(withHeaderAndFooter: Bool) throws -> Array { From a86ac1ca322cc399889f8b914fd04755ff4f4e89 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sun, 19 Jun 2022 01:15:32 +0530 Subject: [PATCH 28/52] Changed a 2048 bit test to a 1024 bit equivalent for faster linux tests --- Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift b/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift index 8ddb246..8176a25 100644 --- a/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift +++ b/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift @@ -1327,7 +1327,7 @@ final class libp2p_cryptoTests: XCTestCase { } func testRSAEncryptedPrivateKeyPemRoundTrip() throws { - let keyPair = try LibP2PCrypto.Keys.KeyPair(.RSA(bits: .B2048)) + let keyPair = try LibP2PCrypto.Keys.KeyPair(.RSA(bits: .B1024)) XCTAssertEqual(keyPair.keyType, .rsa) XCTAssertEqual(keyPair.hasPrivateKey, true) From 9950db36fc2d91521d0539f7cd7312269f61dc5f Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 2 Jul 2022 23:28:42 -0700 Subject: [PATCH 29/52] Moved the PBKDF extension into its own file --- Sources/LibP2PCrypto/PEM/PEM+PBKDF.swift | 97 ++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 Sources/LibP2PCrypto/PEM/PEM+PBKDF.swift diff --git a/Sources/LibP2PCrypto/PEM/PEM+PBKDF.swift b/Sources/LibP2PCrypto/PEM/PEM+PBKDF.swift new file mode 100644 index 0000000..d2d69d1 --- /dev/null +++ b/Sources/LibP2PCrypto/PEM/PEM+PBKDF.swift @@ -0,0 +1,97 @@ +// +// PEM+PBKDF.swift +// +// +// Created by Brandon Toms on 7/1/22. +// + +import Foundation +import CryptoSwift + +// MARK: Encrypted PEM PBKDF Algorithms + +extension PEM { + // MARK: Add support for new PBKDF Algorithms here... + internal enum PBKDFAlgorithm { + case pbkdf2(salt: [UInt8], iterations: Int) + + init(objID:[UInt8], salt:[UInt8], iterations:[UInt8]) throws { + guard let iterations = Int(iterations.toHexString(), radix: 16) else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + switch objID { + case [42, 134, 72, 134, 247, 13, 1, 5, 12]: // pbkdf2 + self = .pbkdf2(salt: salt, iterations: iterations) + default: + throw Error.unsupportedPBKDFAlgorithm(objID) + } + } + + func deriveKey(password:String, ofLength keyLength:Int, usingHashVarient variant:HMAC.Variant = .sha1) throws -> [UInt8] { + switch self { + case .pbkdf2(let salt, let iterations): + //print("Salt: \(salt), Iterations: \(iterations)") + let key = try PKCS5.PBKDF2(password: password.bytes, salt: salt, iterations: iterations, keyLength: keyLength, variant: variant).calculate() + //print(key) + return key + //default: + // throw Error.invalidPEMFormat + } + } + + var objectIdentifier:[UInt8] { + switch self { + case .pbkdf2: + return [42, 134, 72, 134, 247, 13, 1, 5, 12] + } + } + + var salt:[UInt8] { + switch self { + case .pbkdf2(let salt, _): + return salt + } + } + + var iterations:Int { + switch self { + case .pbkdf2(_, let iterations): + return iterations + } + } + + func encodePBKDF() throws -> ASN1.Node { + return .sequence(nodes: [ + .objectIdentifier(data: Data(self.objectIdentifier)), + .sequence(nodes: [ + .octetString(data: Data(self.salt)), + .integer(data: Data(self.iterations.bytes(totalBytes: 2))) + ]) + ]) + } + } + + /// Decodes the PBKDF ASN1 Block in an Encrypted Private Key PEM file + /// - Parameter node: The ASN1 sequence node containing the pbkdf parameters + /// - Returns: The PBKDFAlogrithm if supported + /// + /// Expects an ASN1.Node with the following structure + /// ``` + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), //PBKDF2 //[42,134,72,134,247,13,1,5,12] + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.octetString(data: 8 bytes), //SALT + /// ASN1.Parser.Node.integer(data: 2 bytes) //ITTERATIONS + /// ]) + /// ]) + /// ``` + internal static func decodePBKFD(_ node:ASN1.Node) throws -> PBKDFAlgorithm { + guard case .sequence(let wrapper) = node else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + guard wrapper.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + guard case .objectIdentifier(let objID) = wrapper.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + guard case .sequence(let params) = wrapper.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + guard params.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + guard case .octetString(let salt) = params.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + guard case .integer(let iterations) = params.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } + + return try PBKDFAlgorithm(objID: objID.bytes, salt: salt.bytes, iterations: iterations.bytes) + } +} From aded4c2a8248d4ca7023376d7af0d156d3bef3a6 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 2 Jul 2022 23:29:08 -0700 Subject: [PATCH 30/52] Moved the PEM Cipher extension into its own file --- Sources/LibP2PCrypto/PEM/PEM+Cipher.swift | 109 ++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 Sources/LibP2PCrypto/PEM/PEM+Cipher.swift diff --git a/Sources/LibP2PCrypto/PEM/PEM+Cipher.swift b/Sources/LibP2PCrypto/PEM/PEM+Cipher.swift new file mode 100644 index 0000000..f3fdda9 --- /dev/null +++ b/Sources/LibP2PCrypto/PEM/PEM+Cipher.swift @@ -0,0 +1,109 @@ +// +// PEM+Cipher.swift +// +// +// Created by Brandon Toms on 7/1/22. +// + +import Foundation +import CryptoSwift + +// MARK: Encrypted PEM Cipher Algorithms + +extension PEM { + // MARK: Add support for new Cipher Algorithms here... + internal enum CipherAlgorithm { + case aes_128_cbc(iv:[UInt8]) + case aes_256_cbc(iv:[UInt8]) + //case des3(iv: [UInt8]) + + init(objID:[UInt8], iv:[UInt8]) throws { + switch objID { + case [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02]: // aes-128-cbc + self = .aes_128_cbc(iv: iv) + case [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2a]: // aes-256-cbc + self = .aes_256_cbc(iv: iv) + //case [42, 134, 72, 134, 247, 13, 3, 7]: + // self = .des3(iv: iv) + default: + throw Error.unsupportedCipherAlgorithm(objID) + } + } + + func decrypt(bytes: [UInt8], withKey key:[UInt8]) throws -> [UInt8] { + switch self { + case .aes_128_cbc(let iv): + //print("128 IV: \(iv)") + return try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(bytes) + case .aes_256_cbc(let iv): + //print("256 IV: \(iv)") + return try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(bytes) + //default: + //throw Error.invalidPEMFormat + } + } + + func encrypt(bytes: [UInt8], withKey key:[UInt8]) throws -> [UInt8] { + switch self { + case .aes_128_cbc(let iv): + return try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(bytes) + case .aes_256_cbc(let iv): + return try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(bytes) + } + } + + /// The key length used for this Cipher strategy + /// - Note: we need this information when deriving the key using our PBKDF strategy + var desiredKeyLength:Int { + switch self { + case .aes_128_cbc: return 16 + case .aes_256_cbc: return 32 + } + } + + var objectIdentifier:[UInt8] { + switch self { + case .aes_128_cbc: + return [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02] + case .aes_256_cbc: + return [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2a] + } + } + + var iv:[UInt8] { + switch self { + case .aes_128_cbc(let iv): + return iv + case .aes_256_cbc(let iv): + return iv + } + } + + func encodeCipher() throws -> ASN1.Node { + return .sequence(nodes: [ + .objectIdentifier(data: Data(self.objectIdentifier)), + .octetString(data: Data(self.iv)) + ]) + } + } + + /// Decodes the Cipher ASN1 Block in an Encrypted Private Key PEM file + /// - Parameter node: The ASN1 sequence node containing the cipher parameters + /// - Returns: The CipherAlogrithm if supported + /// + /// Expects an ASN1.Node with the following structure + /// ``` + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), //des-ede3-cbc + /// ASN1.Parser.Node.octetString(data: 16 bytes) //IV + /// ]) + /// ``` + internal static func decodeCipher(_ node:ASN1.Node) throws -> CipherAlgorithm { + guard case .sequence(let params) = node else { throw Error.invalidPEMFormat("EncryptedPrivateKey::CIPHER") } + guard params.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::CIPHER") } + guard case .objectIdentifier(let objID) = params.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::CIPHER") } + guard case .octetString(let initialVector) = params.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::CIPHER") } + + return try CipherAlgorithm(objID: objID.bytes, iv: initialVector.bytes) + } +} From 1e1a6609ab7323002a5b4e46ffa169dd1f57bb43 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 2 Jul 2022 23:29:31 -0700 Subject: [PATCH 31/52] Moved the logic for working with encrypted PEM files into its own file --- Sources/LibP2PCrypto/PEM/PEM+Encrypted.swift | 103 +++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 Sources/LibP2PCrypto/PEM/PEM+Encrypted.swift diff --git a/Sources/LibP2PCrypto/PEM/PEM+Encrypted.swift b/Sources/LibP2PCrypto/PEM/PEM+Encrypted.swift new file mode 100644 index 0000000..da9ffa8 --- /dev/null +++ b/Sources/LibP2PCrypto/PEM/PEM+Encrypted.swift @@ -0,0 +1,103 @@ +// +// PEM+Encrypted.swift +// +// +// Created by Brandon Toms on 7/1/22. +// + +import Foundation +import CryptoSwift + +// MARK: Encrypted PEM + +extension PEM { + + internal struct EncryptedPEM { + let objectIdentifer:[UInt8] + let ciphertext:[UInt8] + let pbkdfAlgorithm:PBKDFAlgorithm + let cipherAlgorithm:CipherAlgorithm + } + + /// Attempts to decode an encrypted Private Key PEM, returning all of the information necessary to decrypt the encrypted PEM + /// - Parameter encryptedPEM: The raw base64 decoded PEM data + /// - Returns: An `EncryptedPEM` Struct containing the ciphertext, the pbkdf alogrithm for key derivation, the cipher algorithm for decrypting and the objectIdentifier describing the contents of this PEM data + /// + /// To decrypt an encrypted PEM Private Key... + /// 1) Strip the headers of the PEM and base64 decode the data + /// 2) Parse the data via ASN1 looking for both the pbkdf and cipher algorithms, their respective parameters (salt, iv and itterations) and the ciphertext (aka octet string)) + /// 3) Derive the encryption key using the appropriate pbkdf alogorithm, found in step 2 + /// 4) Use the encryption key to instantiate the appropriate cipher algorithm, also found in step 2 + /// 5) Decrypt the encrypted ciphertext (the contents of the octetString node) + /// 6) The decrypted octet string can now be handled like any other Private Key PEM + /// + /// ``` + /// sequence(nodes: [ + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), // PEM's ObjectIdentifier + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), // PBKDF Algorithm + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.octetString(data: 8 bytes), // SALT + /// ASN1.Parser.Node.integer(data: 2 bytes) // ITERATIONS + /// ]) + /// ]), + /// ASN1.Parser.Node.sequence(nodes: [ + /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), // Cipher Algorithm (ex: des-ede3-cbc) + /// ASN1.Parser.Node.octetString(data: 16 bytes) // Initial Vector (IV) + /// ]) + /// ]) + /// ]), + /// ASN1.Parser.Node.octetString(data: 640 bytes) + /// ]) + /// ``` + internal static func decodeEncryptedPEM(_ encryptedPEM:Data) throws -> EncryptedPEM { + let asn = try ASN1.Decoder.decode(data: encryptedPEM) + + guard case .sequence(let encryptedPEMWrapper) = asn else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + guard encryptedPEMWrapper.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + guard case .sequence(let encryptionInfoWrapper) = encryptedPEMWrapper.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + guard encryptionInfoWrapper.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + guard case .objectIdentifier(let objID) = encryptionInfoWrapper.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + guard case .sequence(let encryptionAlgorithmsWrapper) = encryptionInfoWrapper.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + guard encryptionAlgorithmsWrapper.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + let pbkdf = try decodePBKFD(encryptionAlgorithmsWrapper.first!) + let cipher = try decodeCipher(encryptionAlgorithmsWrapper.last!) + guard case .octetString(let octets) = encryptedPEMWrapper.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } + + return EncryptedPEM(objectIdentifer: objID.bytes, ciphertext: octets.bytes, pbkdfAlgorithm: pbkdf, cipherAlgorithm: cipher) + } + + internal static func encryptPEM(_ pem:Data, withPassword password:String, usingPBKDF pbkdf:PBKDFAlgorithm = .pbkdf2(salt: try! LibP2PCrypto.randomBytes(length: 8), iterations: 2048), andCipher cipher:CipherAlgorithm = .aes_128_cbc(iv: try! LibP2PCrypto.randomBytes(length: 16))) throws -> Data { + + // Generate Encryption Key from Password + let key = try pbkdf.deriveKey(password: password, ofLength: cipher.desiredKeyLength) + + // Encrypt Plaintext + let ciphertext = try cipher.encrypt(bytes: pem.bytes, withKey: key) + + // Encode Encrypted PEM (including pbkdf and cipher algos used) + let nodes:ASN1.Node = .sequence(nodes: [ + .sequence(nodes: [ + .objectIdentifier(data: Data(hex: "2a864886f70d01050d")), + .sequence(nodes: [ + try pbkdf.encodePBKDF(), + try cipher.encodeCipher() + ]) + ]), + .octetString(data: Data(ciphertext)) + ]) + + let encoded = ASN1.Encoder.encode(nodes) + + let base64 = "\n" + encoded.toBase64().split(intoChunksOfLength: 64).joined(separator: "\n") + "\n" + + return Data(PEM.PEMType.encryptedPrivateKey.headerBytes + base64.bytes + PEM.PEMType.encryptedPrivateKey.footerBytes) + } + + internal static func encryptPEMString(_ pem:Data, withPassword password:String, usingPBKDF pbkdf:PBKDFAlgorithm = .pbkdf2(salt: try! LibP2PCrypto.randomBytes(length: 8), iterations: 2048), andCipher cipher:CipherAlgorithm = .aes_128_cbc(iv: try! LibP2PCrypto.randomBytes(length: 16))) throws -> String { + let data = try PEM.encryptPEM(pem, withPassword: password, usingPBKDF: pbkdf, andCipher: cipher) + return String(data: data, encoding: .utf8)! + } +} From dbef325415f3842c1e8e9259bf58ec739c791d57 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 2 Jul 2022 23:30:17 -0700 Subject: [PATCH 32/52] Moved encrypted PEM logic into separate files for better organization --- Sources/LibP2PCrypto/PEM/PEM.swift | 285 ----------------------------- 1 file changed, 285 deletions(-) diff --git a/Sources/LibP2PCrypto/PEM/PEM.swift b/Sources/LibP2PCrypto/PEM/PEM.swift index 412bf00..e6406a5 100644 --- a/Sources/LibP2PCrypto/PEM/PEM.swift +++ b/Sources/LibP2PCrypto/PEM/PEM.swift @@ -322,288 +322,3 @@ struct PEM { return octet.bytes } } - - -// MARK: Encrypted PEM - -extension PEM { - - internal struct EncryptedPEM { - let objectIdentifer:[UInt8] - let ciphertext:[UInt8] - let pbkdfAlgorithm:PBKDFAlgorithm - let cipherAlgorithm:CipherAlgorithm - } - - /// Attempts to decode an encrypted Private Key PEM, returning all of the information necessary to decrypt the encrypted PEM - /// - Parameter encryptedPEM: The raw base64 decoded PEM data - /// - Returns: An `EncryptedPEM` Struct containing the ciphertext, the pbkdf alogrithm for key derivation, the cipher algorithm for decrypting and the objectIdentifier describing the contents of this PEM data - /// - /// To decrypt an encrypted PEM Private Key... - /// 1) Strip the headers of the PEM and base64 decode the data - /// 2) Parse the data via ASN1 looking for both the pbkdf and cipher algorithms, their respective parameters (salt, iv and itterations) and the ciphertext (aka octet string)) - /// 3) Derive the encryption key using the appropriate pbkdf alogorithm, found in step 2 - /// 4) Use the encryption key to instantiate the appropriate cipher algorithm, also found in step 2 - /// 5) Decrypt the encrypted ciphertext (the contents of the octetString node) - /// 6) The decrypted octet string can now be handled like any other Private Key PEM - /// - /// ``` - /// sequence(nodes: [ - /// ASN1.Parser.Node.sequence(nodes: [ - /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), // PEM's ObjectIdentifier - /// ASN1.Parser.Node.sequence(nodes: [ - /// ASN1.Parser.Node.sequence(nodes: [ - /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), // PBKDF Algorithm - /// ASN1.Parser.Node.sequence(nodes: [ - /// ASN1.Parser.Node.octetString(data: 8 bytes), // SALT - /// ASN1.Parser.Node.integer(data: 2 bytes) // ITERATIONS - /// ]) - /// ]), - /// ASN1.Parser.Node.sequence(nodes: [ - /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), // Cipher Algorithm (ex: des-ede3-cbc) - /// ASN1.Parser.Node.octetString(data: 16 bytes) // Initial Vector (IV) - /// ]) - /// ]) - /// ]), - /// ASN1.Parser.Node.octetString(data: 640 bytes) - /// ]) - /// ``` - internal static func decodeEncryptedPEM(_ encryptedPEM:Data) throws -> EncryptedPEM { - let asn = try ASN1.Decoder.decode(data: encryptedPEM) - - guard case .sequence(let encryptedPEMWrapper) = asn else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } - guard encryptedPEMWrapper.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } - guard case .sequence(let encryptionInfoWrapper) = encryptedPEMWrapper.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } - guard encryptionInfoWrapper.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } - guard case .objectIdentifier(let objID) = encryptionInfoWrapper.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } - guard case .sequence(let encryptionAlgorithmsWrapper) = encryptionInfoWrapper.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } - guard encryptionAlgorithmsWrapper.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } - let pbkdf = try decodePBKFD(encryptionAlgorithmsWrapper.first!) - let cipher = try decodeCipher(encryptionAlgorithmsWrapper.last!) - guard case .octetString(let octets) = encryptedPEMWrapper.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::") } - - return EncryptedPEM(objectIdentifer: objID.bytes, ciphertext: octets.bytes, pbkdfAlgorithm: pbkdf, cipherAlgorithm: cipher) - } - - internal static func encryptPEM(_ pem:Data, withPassword password:String, usingPBKDF pbkdf:PBKDFAlgorithm = .pbkdf2(salt: try! LibP2PCrypto.randomBytes(length: 8), iterations: 2048), andCipher cipher:CipherAlgorithm = .aes_128_cbc(iv: try! LibP2PCrypto.randomBytes(length: 16))) throws -> Data { - - // Generate Encryption Key from Password - let key = try pbkdf.deriveKey(password: password, ofLength: cipher.desiredKeyLength) - - // Encrypt Plaintext - let ciphertext = try cipher.encrypt(bytes: pem.bytes, withKey: key) - - // Encode Encrypted PEM (including pbkdf and cipher algos used) - let nodes:ASN1.Node = .sequence(nodes: [ - .sequence(nodes: [ - .objectIdentifier(data: Data(hex: "2a864886f70d01050d")), - .sequence(nodes: [ - try pbkdf.encodePBKDF(), - try cipher.encodeCipher() - ]) - ]), - .octetString(data: Data(ciphertext)) - ]) - - let encoded = ASN1.Encoder.encode(nodes) - - let base64 = "\n" + encoded.toBase64().split(intoChunksOfLength: 64).joined(separator: "\n") + "\n" - - return Data(PEM.PEMType.encryptedPrivateKey.headerBytes + base64.bytes + PEM.PEMType.encryptedPrivateKey.footerBytes) - } - - internal static func encryptPEMString(_ pem:Data, withPassword password:String, usingPBKDF pbkdf:PBKDFAlgorithm = .pbkdf2(salt: try! LibP2PCrypto.randomBytes(length: 8), iterations: 2048), andCipher cipher:CipherAlgorithm = .aes_128_cbc(iv: try! LibP2PCrypto.randomBytes(length: 16))) throws -> String { - let data = try PEM.encryptPEM(pem, withPassword: password, usingPBKDF: pbkdf, andCipher: cipher) - return String(data: data, encoding: .utf8)! - } -} - - -// MARK: Encrypted PEM PBKDF Algorithms - -extension PEM { - // MARK: Add support for new PBKDF Algorithms here... - internal enum PBKDFAlgorithm { - case pbkdf2(salt: [UInt8], iterations: Int) - - init(objID:[UInt8], salt:[UInt8], iterations:[UInt8]) throws { - guard let iterations = Int(iterations.toHexString(), radix: 16) else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } - switch objID { - case [42, 134, 72, 134, 247, 13, 1, 5, 12]: // pbkdf2 - self = .pbkdf2(salt: salt, iterations: iterations) - default: - throw Error.unsupportedPBKDFAlgorithm(objID) - } - } - - func deriveKey(password:String, ofLength keyLength:Int, usingHashVarient variant:HMAC.Variant = .sha1) throws -> [UInt8] { - switch self { - case .pbkdf2(let salt, let iterations): - //print("Salt: \(salt), Iterations: \(iterations)") - let key = try PKCS5.PBKDF2(password: password.bytes, salt: salt, iterations: iterations, keyLength: keyLength, variant: variant).calculate() - //print(key) - return key - //default: - // throw Error.invalidPEMFormat - } - } - - var objectIdentifier:[UInt8] { - switch self { - case .pbkdf2: - return [42, 134, 72, 134, 247, 13, 1, 5, 12] - } - } - - var salt:[UInt8] { - switch self { - case .pbkdf2(let salt, _): - return salt - } - } - - var iterations:Int { - switch self { - case .pbkdf2(_, let iterations): - return iterations - } - } - - func encodePBKDF() throws -> ASN1.Node { - return .sequence(nodes: [ - .objectIdentifier(data: Data(self.objectIdentifier)), - .sequence(nodes: [ - .octetString(data: Data(self.salt)), - .integer(data: Data(self.iterations.bytes(totalBytes: 2))) - ]) - ]) - } - } - - /// Decodes the PBKDF ASN1 Block in an Encrypted Private Key PEM file - /// - Parameter node: The ASN1 sequence node containing the pbkdf parameters - /// - Returns: The PBKDFAlogrithm if supported - /// - /// Expects an ASN1.Node with the following structure - /// ``` - /// ASN1.Parser.Node.sequence(nodes: [ - /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), //PBKDF2 //[42,134,72,134,247,13,1,5,12] - /// ASN1.Parser.Node.sequence(nodes: [ - /// ASN1.Parser.Node.octetString(data: 8 bytes), //SALT - /// ASN1.Parser.Node.integer(data: 2 bytes) //ITTERATIONS - /// ]) - /// ]) - /// ``` - fileprivate static func decodePBKFD(_ node:ASN1.Node) throws -> PBKDFAlgorithm { - guard case .sequence(let wrapper) = node else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } - guard wrapper.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } - guard case .objectIdentifier(let objID) = wrapper.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } - guard case .sequence(let params) = wrapper.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } - guard params.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } - guard case .octetString(let salt) = params.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } - guard case .integer(let iterations) = params.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::PBKDF") } - - return try PBKDFAlgorithm(objID: objID.bytes, salt: salt.bytes, iterations: iterations.bytes) - } -} - - -// MARK: Encrypted PEM Cipher Algorithms - -extension PEM { - // MARK: Add support for new Cipher Algorithms here... - internal enum CipherAlgorithm { - case aes_128_cbc(iv:[UInt8]) - case aes_256_cbc(iv:[UInt8]) - //case des3(iv: [UInt8]) - - init(objID:[UInt8], iv:[UInt8]) throws { - switch objID { - case [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02]: // aes-128-cbc - self = .aes_128_cbc(iv: iv) - case [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2a]: // aes-256-cbc - self = .aes_256_cbc(iv: iv) - //case [42, 134, 72, 134, 247, 13, 3, 7]: - // self = .des3(iv: iv) - default: - throw Error.unsupportedCipherAlgorithm(objID) - } - } - - func decrypt(bytes: [UInt8], withKey key:[UInt8]) throws -> [UInt8] { - switch self { - case .aes_128_cbc(let iv): - //print("128 IV: \(iv)") - return try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(bytes) - case .aes_256_cbc(let iv): - //print("256 IV: \(iv)") - return try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(bytes) - //default: - //throw Error.invalidPEMFormat - } - } - - func encrypt(bytes: [UInt8], withKey key:[UInt8]) throws -> [UInt8] { - switch self { - case .aes_128_cbc(let iv): - return try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(bytes) - case .aes_256_cbc(let iv): - return try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(bytes) - } - } - - /// The key length used for this Cipher strategy - /// - Note: we need this information when deriving the key using our PBKDF strategy - var desiredKeyLength:Int { - switch self { - case .aes_128_cbc: return 16 - case .aes_256_cbc: return 32 - } - } - - var objectIdentifier:[UInt8] { - switch self { - case .aes_128_cbc: - return [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02] - case .aes_256_cbc: - return [0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2a] - } - } - - var iv:[UInt8] { - switch self { - case .aes_128_cbc(let iv): - return iv - case .aes_256_cbc(let iv): - return iv - } - } - - func encodeCipher() throws -> ASN1.Node { - return .sequence(nodes: [ - .objectIdentifier(data: Data(self.objectIdentifier)), - .octetString(data: Data(self.iv)) - ]) - } - } - - /// Decodes the Cipher ASN1 Block in an Encrypted Private Key PEM file - /// - Parameter node: The ASN1 sequence node containing the cipher parameters - /// - Returns: The CipherAlogrithm if supported - /// - /// Expects an ASN1.Node with the following structure - /// ``` - /// ASN1.Parser.Node.sequence(nodes: [ - /// ASN1.Parser.Node.objectIdentifier(data: 9 bytes), //des-ede3-cbc - /// ASN1.Parser.Node.octetString(data: 16 bytes) //IV - /// ]) - /// ``` - fileprivate static func decodeCipher(_ node:ASN1.Node) throws -> CipherAlgorithm { - guard case .sequence(let params) = node else { throw Error.invalidPEMFormat("EncryptedPrivateKey::CIPHER") } - guard params.count == 2 else { throw Error.invalidPEMFormat("EncryptedPrivateKey::CIPHER") } - guard case .objectIdentifier(let objID) = params.first else { throw Error.invalidPEMFormat("EncryptedPrivateKey::CIPHER") } - guard case .octetString(let initialVector) = params.last else { throw Error.invalidPEMFormat("EncryptedPrivateKey::CIPHER") } - - return try CipherAlgorithm(objID: objID.bytes, iv: initialVector.bytes) - } -} From d19f353ea7c1496db1f76756e7df3287820a2fb4 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sat, 2 Jul 2022 23:31:00 -0700 Subject: [PATCH 33/52] Updated a comment --- Sources/LibP2PCrypto/PEM/DER.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/LibP2PCrypto/PEM/DER.swift b/Sources/LibP2PCrypto/PEM/DER.swift index 3bd50c7..74f466a 100644 --- a/Sources/LibP2PCrypto/PEM/DER.swift +++ b/Sources/LibP2PCrypto/PEM/DER.swift @@ -207,7 +207,7 @@ public extension DEREncodable { } } -/// Conform to this protocol if your type can both be instantiated and expressed by an ASN1 DER representation. +/// Conform to this protocol if your type can both be instantiated and expressed as an ASN1 DER representation. public protocol DERCodable: DERDecodable, DEREncodable { } struct DER { From 869e7fe23449b17a9c696e5537b1ed332dc9e5b8 Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Thu, 14 Jul 2022 07:44:10 -0700 Subject: [PATCH 34/52] Added RSABitLength initializer --- Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift index bd5db78..c51804a 100644 --- a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift +++ b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift @@ -107,7 +107,7 @@ struct RSAPrivateKey:CommonPrivateKey { } /// Initializes a new RSA key (backed by CryptoSwift) of the specified bit size - init(keySize: Int) throws { + internal init(keySize: Int) throws { switch keySize { case 1024: self.key = CryptoSwift.RSA(keySize: keySize) @@ -122,6 +122,10 @@ struct RSAPrivateKey:CommonPrivateKey { } } + init(keySize: LibP2PCrypto.Keys.RSABitLength) throws { + try self.init(keySize: keySize.bits) + } + /// Expects the ASN1 Encoding of the DER formatted RSA Private Key init(rawRepresentation raw: Data) throws { guard case .sequence(let params) = try ASN1.Decoder.decode(data: raw) else { throw NSError(domain: "Invalid ASN1 Encoding -> No PrivKey Sequence", code: 0) } From 2f2ab121e76aa37b180dc0731a8cd552cb806a4e Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Thu, 14 Jul 2022 07:47:48 -0700 Subject: [PATCH 35/52] Added RSAExternalRepresentation test --- .../FixtureGenerationTests.swift | 294 +++++++++++++++ .../LibP2PCryptoTests/LibP2PCryptoTests.swift | 71 +++- Tests/LibP2PCryptoTests/fixtures.swift | 348 ++++++++++++++++++ 3 files changed, 706 insertions(+), 7 deletions(-) create mode 100644 Tests/LibP2PCryptoTests/FixtureGenerationTests.swift create mode 100644 Tests/LibP2PCryptoTests/fixtures.swift diff --git a/Tests/LibP2PCryptoTests/FixtureGenerationTests.swift b/Tests/LibP2PCryptoTests/FixtureGenerationTests.swift new file mode 100644 index 0000000..e9aee1d --- /dev/null +++ b/Tests/LibP2PCryptoTests/FixtureGenerationTests.swift @@ -0,0 +1,294 @@ +// +// FixtureGenerationTests.swift +// +// +// Created by Brandon Toms on 7/7/22. +// + +import XCTest +@testable import LibP2PCrypto + +final class FixtureGenerationTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testCreateRSATestFixture() throws { + + let fixtures = [1024, 2048, 3072, 4096] + let keyType = "RSA" + + for fixture in fixtures { + let keySize = fixture + let message = "LibP2P RSA Keys!" + + /// Generate a SecKey RSA Key + let parameters: [CFString: Any] = [ + kSecAttrKeyType: kSecAttrKeyTypeRSA, + kSecAttrKeySizeInBits: keySize + ] + + var error: Unmanaged? + + // Generate the RSA SecKey + guard let rsaSecKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else { + XCTFail("Key Generation Error: \(error.debugDescription)") + return + } + + // Extract the public key from the private RSA SecKey + guard let rsaSecKeyPublic = SecKeyCopyPublicKey(rsaSecKey) else { + XCTFail("Public Key Extraction Error") + return + } + + /// Lets grab the external representation of the public key + var publicExternalRepError: Unmanaged? + guard let publicRSASecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKeyPublic, &publicExternalRepError) as? Data else { + XCTFail("Failed to copy external representation for RSA SecKey") + return + } + + /// Lets grab the external representation of the public key + var privateExternalRepError: Unmanaged? + guard let privateRSASecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &privateExternalRepError) as? Data else { + XCTFail("Failed to copy external representation for RSA SecKey") + return + } + + guard let rsaKey = try? RSAPrivateKey(rawRepresentation: privateRSASecKeyRawRep) else { + XCTFail("Failed to import SecKey as RSAPrivateKey") + return + } + + var template = FixtureTemplate + template = template.replacingOccurrences(of: "{{KEY_TYPE}}", with: keyType) + template = template.replacingOccurrences(of: "{{KEY_SIZE}}", with: "_\(keySize)") + + // DERs + template = template.replacingOccurrences(of: "{{PUBLIC_DER}}", with: "\(publicRSASecKeyRawRep.base64EncodedString())") + template = template.replacingOccurrences(of: "{{PRIVATE_DER}}", with: "\(privateRSASecKeyRawRep.base64EncodedString())") + + // PEMs + template = template.replacingOccurrences(of: "{{PUBLIC_PEM}}", with: try rsaKey.exportPublicKeyPEMString(withHeaderAndFooter: true)) + template = template.replacingOccurrences(of: "{{PRIVATE_PEM}}", with: try rsaKey.exportPrivateKeyPEMString(withHeaderAndFooter: true)) + + // Encrypted PEMs + template = template.replacingOccurrences(of: "{{ENCRYPTED_PEMS}}", with: "") + template = template.replacingOccurrences(of: "{{ENCRYPTION_PASSWORD}}", with: "") + + // Marshaled + template = template.replacingOccurrences(of: "{{PUBLIC_MARSHALED}}", with: try rsaKey.derivePublicKey().marshal().base64EncodedString()) + template = template.replacingOccurrences(of: "{{PRIVATE_MARSHALED}}", with: try rsaKey.marshal().base64EncodedString()) + + // Plaintext Message + template = template.replacingOccurrences(of: "{{PLAINTEXT_MESSAGE}}", with: message) + + let encryptedMessages = try encrypt(data: message.data(using: .utf8)!, with: rsaSecKeyPublic) + template = template.replacingOccurrences(of: "{{ENCRYPTED_MESSAGES}}", with: encryptedMessages.joined(separator: ",\n\t ")) + + let signedMessages = try sign(message: message.data(using: .utf8)!, using: rsaSecKey) + template = template.replacingOccurrences(of: "{{SIGNED_MESSAGES}}", with: signedMessages.joined(separator: ",\n\t ")) + + print(template) + } + } + + func testCreateED25519TestFixture() throws { + + let message = "LibP2P ED25519 Keys!" + let keySize:Int? = nil + let keyType = "ED25519" + + // Generate the RSA SecKey + guard let edKey = try? LibP2PCrypto.Keys.KeyPair(.Ed25519) else { + XCTFail("Key Generation Error") + return + } + + var template = FixtureTemplate + template = template.replacingOccurrences(of: "{{KEY_TYPE}}", with: keyType) + template = template.replacingOccurrences(of: "{{KEY_SIZE}}", with: keySize != nil ? "_\(keySize!)" : "") + + // DERs + template = template.replacingOccurrences(of: "{{PUBLIC_DER}}", with: "\(try edKey.publicKey.publicKeyDER().asString(base: .base64Pad))") + template = template.replacingOccurrences(of: "{{PRIVATE_DER}}", with: "\(try edKey.privateKey!.privateKeyDER().asString(base: .base64Pad))") + + // PEMs + template = template.replacingOccurrences(of: "{{PUBLIC_PEM}}", with: try edKey.exportPublicPEMString(withHeaderAndFooter: true)) + template = template.replacingOccurrences(of: "{{PRIVATE_PEM}}", with: try edKey.exportPrivatePEMString(withHeaderAndFooter: true)) + + // Encrypted PEMs + template = template.replacingOccurrences(of: "{{ENCRYPTED_PEMS}}", with: "") + template = template.replacingOccurrences(of: "{{ENCRYPTION_PASSWORD}}", with: "") + + // Marshaled + template = template.replacingOccurrences(of: "{{PUBLIC_MARSHALED}}", with: try edKey.publicKey.marshal().base64EncodedString()) + template = template.replacingOccurrences(of: "{{PRIVATE_MARSHALED}}", with: try edKey.privateKey!.marshal().base64EncodedString()) + + // Plaintext Message + template = template.replacingOccurrences(of: "{{PLAINTEXT_MESSAGE}}", with: message) + + // TODO: Add algorithm prefix + let encryptedMessages = [try edKey.encrypt(data: message.data(using: .utf8)!).base64EncodedString()] + template = template.replacingOccurrences(of: "{{ENCRYPTED_MESSAGES}}", with: encryptedMessages.joined(separator: ",\n\t ")) + + let signedMessages = [try edKey.sign(message: message.data(using: .utf8)!).base64EncodedString()] + template = template.replacingOccurrences(of: "{{SIGNED_MESSAGES}}", with: signedMessages.joined(separator: ",\n\t ")) + +// let encryptedMessages = try encrypt(data: message.data(using: .utf8)!, with: edKey) +// template = template.replacingOccurrences(of: "{{ENCRYPTED_MESSAGES}}", with: encryptedMessages.joined(separator: ",\n\t ")) +// +// let signedMessages = try sign(message: message.data(using: .utf8)!, using: edKey) +// template = template.replacingOccurrences(of: "{{SIGNED_MESSAGES}}", with: signedMessages.joined(separator: ",\n\t ")) + + print(template) + } + + private let FixtureTemplate = """ +static let {{KEY_TYPE}}{{KEY_SIZE}} = Fixture( + keySize: {{KEY_SIZE}}, + publicDER: \"\"\" +{{PUBLIC_DER}} +\"\"\", + privateDER: \"\"\" +{{PRIVATE_DER}} +\"\"\", + publicPEM: \"\"\" +{{PUBLIC_PEM}} +\"\"\", + privatePEM: \"\"\" +{{PRIVATE_PEM}} +\"\"\", + encryptedPEM: [ +{{ENCRYPTED_PEMS}} + ], + encryptionPassword: \"{{ENCRYPTION_PASSWORD}}\", + publicMarshaled: \"\"\" +{{PUBLIC_MARSHALED}} +\"\"\", + privateMarshaled: \"\"\" +{{PRIVATE_MARSHALED}} +\"\"\", + rawMessage: "{{PLAINTEXT_MESSAGE}}", + encryptedMessage: [ + {{ENCRYPTED_MESSAGES}} + ], + signedMessages: [ + {{SIGNED_MESSAGES}} + ] +) +""" + + //private func printHexData16BytesWide(_ bytes:[UInt8]) { +// print(bytes.toHexString().split(intoChunksOfLength: 32).map { $0.split(intoChunksOfLength: 2).map { "0x\($0.uppercased())" }.joined(separator: ", ") }.joined(separator: ",\n")) + //} + + private func initSecKey(rawRepresentation raw: Data) throws -> SecKey { + let attributes: [String: Any] = [ + kSecAttrKeyType as String: kSecAttrKeyTypeRSA, + kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, + kSecAttrKeySizeInBits as String: 1024, + kSecAttrIsPermanent as String: false + ] + + var error: Unmanaged? + guard let secKey = SecKeyCreateWithData(raw as CFData, attributes as CFDictionary, &error) else { + throw NSError(domain: "Error constructing SecKey from raw key data: \(error.debugDescription)", code: 0, userInfo: nil) + } + + return secKey + } + + private func sign(message: Data, using key: SecKey) throws -> [String] { + let algorithms: [SecKeyAlgorithm] = [ + .rsaSignatureRaw, + //.rsaSignatureDigestPSSSHA1, + //.rsaSignatureDigestPSSSHA224, + //.rsaSignatureDigestPSSSHA256, + //.rsaSignatureDigestPSSSHA384, + //.rsaSignatureDigestPSSSHA512, + .rsaSignatureDigestPKCS1v15Raw, + .rsaSignatureDigestPKCS1v15SHA1, + .rsaSignatureDigestPKCS1v15SHA224, + .rsaSignatureDigestPKCS1v15SHA256, + .rsaSignatureDigestPKCS1v15SHA384, + .rsaSignatureDigestPKCS1v15SHA512, + //.rsaSignatureMessagePSSSHA1, + //.rsaSignatureMessagePSSSHA224, + //.rsaSignatureMessagePSSSHA256, + //.rsaSignatureMessagePSSSHA384, + //.rsaSignatureMessagePSSSHA512, + .rsaSignatureMessagePKCS1v15SHA1, + .rsaSignatureMessagePKCS1v15SHA224, + .rsaSignatureMessagePKCS1v15SHA256, + .rsaSignatureMessagePKCS1v15SHA384, + .rsaSignatureMessagePKCS1v15SHA512, + ] + + var sigs: [String] = [] + + for algo in algorithms { + var error: Unmanaged? + + // Sign the data + guard let signature = SecKeyCreateSignature( + key, + algo, + message as CFData, + &error + ) as Data? + else { print("\"\(algo.rawValue)\": \"nil\","); continue } + + // Throw the error if we encountered one + if let error = error { print("\"\(algo.rawValue)\": \"\(error.takeRetainedValue())\","); continue } + + // Append the signature + sigs.append("\"\(algo.rawValue)\": \"\(signature.base64EncodedString())\"") + } + + return sigs + } + + private func encrypt(data: Data, with key: SecKey) throws -> [String] { + let algorithms: [SecKeyAlgorithm] = [ + .rsaEncryptionRaw, + .rsaEncryptionPKCS1 + ] + + var encryptions: [String] = [] + + for algo in algorithms { + var error: Unmanaged? + guard let encryptedData = SecKeyCreateEncryptedData(key, algo, data as CFData, &error) as? Data else { + print("\"\(algo.rawValue)\": \"\(error?.takeRetainedValue().localizedDescription ?? "nil")\","); continue + } + encryptions.append("\"\(algo.rawValue)\": \"\(encryptedData.base64EncodedString())\"") + } + + return encryptions + } + +} + +struct TestFixtures { + struct Fixture { + let keySize: Int + let publicDER: String + let privateDER: String + let publicPEM:String + let privatePEM:String + let encryptedPEM:[String:String] + let encryptionPassword:String + let publicMarshaled:String + let privateMarshaled:String + let rawMessage: String + let encryptedMessage: [String: String] + let signedMessages: [String: String] + } +} diff --git a/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift b/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift index 8176a25..3e52483 100644 --- a/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift +++ b/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift @@ -73,6 +73,63 @@ final class libp2p_cryptoTests: XCTestCase { XCTAssertEqual(attributes?.size, 4096) XCTAssertEqual(attributes?.isPrivate, true) } + + /// This test ensures that SecKey's CopyExternalRepresentation outputs the same data as our CryptoSwift RSA Implementation + func testRSAExternalRepresentation() throws { + /// Generate a SecKey RSA Key + let parameters:[CFString:Any] = [ + kSecAttrKeyType: kSecAttrKeyTypeRSA, + kSecAttrKeySizeInBits: 1024 + ] + + var error:Unmanaged? = nil + + guard let privKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else { + print(error.debugDescription) + throw NSError(domain: "Key Generation Error: \(error.debugDescription)", code: 0, userInfo: nil) + } + + let rsaSecKey = privKey + + /// Lets grab the external representation + var externalRepError:Unmanaged? + guard let cfdata = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) else { + XCTFail("Failed to copy external representation for RSA SecKey") + return + } + + let rsaSecKeyRawRep = cfdata as Data + + print(rsaSecKeyRawRep.asString(base: .base16)) + + + /// Ensure we can import the RSA key as a CryptoSwift RSA Key + guard case .sequence(let params) = try ASN1.Decoder.decode(data: rsaSecKeyRawRep) else { throw NSError(domain: "Invalid ASN1 Encoding -> No PrivKey Sequence", code: 0) } + // We check for 4 here because internally we can only marshal the first 4 integers at the moment... + guard params.count == 4 || params.count == 9 else { throw NSError(domain: "Invalid ASN1 Encoding -> Invalid Private RSA param count. Expected 9 got \(params.count)", code: 0) } + guard case .integer(let n) = params[1] else { throw NSError(domain: "Invalid ASN1 Encoding -> PrivKey No Modulus", code: 0) } + guard case .integer(let e) = params[2] else { throw NSError(domain: "Invalid ASN1 Encoding -> PrivKey No Public Exponent", code: 0) } + guard case .integer(let d) = params[3] else { throw NSError(domain: "Invalid ASN1 Encoding -> PrivKey No Private Exponent", code: 0) } + + let rsaCryptoSwift = RSA(n: n.bytes, e: e.bytes, d: d.bytes) + + // Raw Rep + guard let d = rsaCryptoSwift.d else { XCTFail("Failed to import RSA SecKey as private CryptoSwift Key"); return } + let mod = rsaCryptoSwift.n.serialize() + let privkeyAsnNode:ASN1.Node = + .sequence(nodes: [ + .integer(data: Data( Array(arrayLiteral: 0x00) )), + .integer(data: Data(DER.i2osp(x: mod.bytes, size: mod.count + 1))), + .integer(data: rsaCryptoSwift.e.serialize()), + .integer(data: d.serialize()) + ]) + + let rsaCryptoSwiftRawRep = Data(ASN1.Encoder.encode(privkeyAsnNode)) + + + print(rsaCryptoSwiftRawRep.asString(base: .base16)) + + } #endif func testED25519() throws { @@ -363,27 +420,27 @@ final class libp2p_cryptoTests: XCTestCase { let rsa = try LibP2PCrypto.Keys.KeyPair(marshaledPrivateKey: TestFixtures.RSA_1024.privateMarshaled, base: .base64Pad) let signedData = try rsa.privateKey!.sign(message: message) - + print(signedData.asString(base: .base64Pad)) - + XCTAssertEqual(signedData.asString(base: .base64Pad), TestFixtures.RSA_1024.signedMessages["algid:sign:RSA:message-PKCS1v15:SHA256"]) XCTAssertNotEqual(message, signedData) - + // This just ensures that a newly instantiated Pub SecKey matches the derived pubkey from the keypair... let recoveredPubKey:RSAPublicKey = try RSAPublicKey(rawRepresentation: rsa.publicKey.data) XCTAssertEqual(rsa.publicKey.data, recoveredPubKey.rawRepresentation) XCTAssertEqual(try rsa.marshalPublicKey().asString(base: .base64Pad), TestFixtures.RSA_1024.publicMarshaled) - + // Ensure the rsaSignatureMessagePKCS1v15SHA256 algorithm works with our RSA KeyPair //XCTAssertTrue(SecKeyIsAlgorithmSupported(recoveredPubKey, .verify, .rsaSignatureMessagePKCS1v15SHA256)) - + // Ensure the Signed Data is Valid for the given message XCTAssertTrue(try rsa.publicKey.verify(signature: signedData, for: message)) - + // Ensure that the signature is no longer valid if it is tweaked in any way XCTAssertThrowsError(try rsa.publicKey.verify(signature: Data(signedData.shuffled()), for: message)) XCTAssertThrowsError(try rsa.publicKey.verify(signature: Data(signedData.dropFirst()), for: message)) - + // Ensure that the signature is no longer valid if the message is tweaked in any way XCTAssertThrowsError(try rsa.publicKey.verify(signature: signedData, for: Data(message.shuffled()))) XCTAssertThrowsError(try rsa.publicKey.verify(signature: signedData, for: Data(message.dropFirst()))) diff --git a/Tests/LibP2PCryptoTests/fixtures.swift b/Tests/LibP2PCryptoTests/fixtures.swift new file mode 100644 index 0000000..c3ee991 --- /dev/null +++ b/Tests/LibP2PCryptoTests/fixtures.swift @@ -0,0 +1,348 @@ +// +// fixtures.swift +// +// +// Created by Brandon Toms on 6/6/22. +// + +import Foundation + +extension TestFixtures { + static let RSA_1024 = Fixture( + keySize: 1024, + publicDER: """ + MIGJAoGBALs3YIii1qV6Q01m2CZ5I+4ZJUttX13AbzK+QbWTNgRhwOneo7ZoWXtLwGfmyDYv+B0aOzjwC7Nh3+iKhLD4BQasZxBjzTirjrLib4TMMruWVCkmIWft5fLnoW7Q0gu/yIlRlKw1r/fqVWgVCLezZCJ+v5LJvbUfjdo6ffaqcKoRAgMBAAE= + """, + privateDER: """ + MIICXQIBAAKBgQC7N2CIotalekNNZtgmeSPuGSVLbV9dwG8yvkG1kzYEYcDp3qO2aFl7S8Bn5sg2L/gdGjs48AuzYd/oioSw+AUGrGcQY804q46y4m+EzDK7llQpJiFn7eXy56Fu0NILv8iJUZSsNa/36lVoFQi3s2Qifr+Syb21H43aOn32qnCqEQIDAQABAoGBAJ6hO3BK2aj4wZIR9FAVEPar48fXcpjTduT+BFs/0uM/mOAQv5LNNBSeiPcAut//ITI3ibqi2qcx5TD6PZhdbpNXtIvPf1/DtjsZiYupTd61KVBnxDn2v0z6LsSDfTe3rhXMmgPxfNQtNKxMhvM0d0vRwxSFA+OleG8PFXFuAczpAkEA47azreYAfdmMcD52Mvam0N7BpPlMEv3Tk6eMawy7aWKIqvE5FYHAZufMNO4bX9Jd0EoOChYKHa2g4ZewVXwajwJBANJ428iiHfzxGLDGkSKEW8pDIzbk2TAyhZLb/TfRfPpOvgW1kKH9HuByf3ZZ6wYd+E9ZHnC/CctbMSJeYmtTwV8CQCnAJdGMiiqI6KbrzOArOQqyzO5ihwA0acZ4wdYez33TAxvUfpLi51P2zAooXfyDpY+7BDf1MoWegBDcrwf9aSECQQCTkyqIAyQDtwkY6iHZkfTKXUjTtKKUqNf/oUBrYve+ineyiRxgeJqtxZqZ4XJpV5pECLjPVSQI8mgBMSzRFGkBAkAXssWCIWVbBqcKO5xQM9juuqjmFDf2x9opay0C9MOASo7Af8LIM4moz1sVwU/H8PLKvUhlmVCX9kaF7b0PWBjl + """, + publicPEM: """ + -----BEGIN PUBLIC KEY----- + MIG1MA0GCSqGSIb3DQEBAQUAA4GjADCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC + gYEAuzdgiKLWpXpDTWbYJnkj7hklS21fXcBvMr5BtZM2BGHA6d6jtmhZe0vAZ+bI + Ni/4HRo7OPALs2Hf6IqEsPgFBqxnEGPNOKuOsuJvhMwyu5ZUKSYhZ+3l8uehbtDS + C7/IiVGUrDWv9+pVaBUIt7NkIn6/ksm9tR+N2jp99qpwqhECAwEAAQ== + -----END PUBLIC KEY----- + """, + privatePEM: """ + -----BEGIN PRIVATE KEY----- + MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALs3YIii1qV6Q01m + 2CZ5I+4ZJUttX13AbzK+QbWTNgRhwOneo7ZoWXtLwGfmyDYv+B0aOzjwC7Nh3+iK + hLD4BQasZxBjzTirjrLib4TMMruWVCkmIWft5fLnoW7Q0gu/yIlRlKw1r/fqVWgV + CLezZCJ+v5LJvbUfjdo6ffaqcKoRAgMBAAECgYEAnqE7cErZqPjBkhH0UBUQ9qvj + x9dymNN25P4EWz/S4z+Y4BC/ks00FJ6I9wC63/8hMjeJuqLapzHlMPo9mF1uk1e0 + i89/X8O2OxmJi6lN3rUpUGfEOfa/TPouxIN9N7euFcyaA/F81C00rEyG8zR3S9HD + FIUD46V4bw8VcW4BzOkCQQDjtrOt5gB92YxwPnYy9qbQ3sGk+UwS/dOTp4xrDLtp + Yoiq8TkVgcBm58w07htf0l3QSg4KFgodraDhl7BVfBqPAkEA0njbyKId/PEYsMaR + IoRbykMjNuTZMDKFktv9N9F8+k6+BbWQof0e4HJ/dlnrBh34T1kecL8Jy1sxIl5i + a1PBXwJAKcAl0YyKKojopuvM4Cs5CrLM7mKHADRpxnjB1h7PfdMDG9R+kuLnU/bM + Cihd/IOlj7sEN/UyhZ6AENyvB/1pIQJBAJOTKogDJAO3CRjqIdmR9MpdSNO0opSo + 1/+hQGti976Kd7KJHGB4mq3FmpnhcmlXmkQIuM9VJAjyaAExLNEUaQECQBeyxYIh + ZVsGpwo7nFAz2O66qOYUN/bH2ilrLQL0w4BKjsB/wsgziajPWxXBT8fw8sq9SGWZ + UJf2RoXtvQ9YGOU= + -----END PRIVATE KEY----- + """, + encryptedPEM: [:], + encryptionPassword: "", + publicMarshaled: """ + CAASogEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALs3YIii1qV6Q01m2CZ5I+4ZJUttX13AbzK+QbWTNgRhwOneo7ZoWXtLwGfmyDYv+B0aOzjwC7Nh3+iKhLD4BQasZxBjzTirjrLib4TMMruWVCkmIWft5fLnoW7Q0gu/yIlRlKw1r/fqVWgVCLezZCJ+v5LJvbUfjdo6ffaqcKoRAgMBAAE= + """, + privateMarshaled: """ + CAAS4QQwggJdAgEAAoGBALs3YIii1qV6Q01m2CZ5I+4ZJUttX13AbzK+QbWTNgRhwOneo7ZoWXtLwGfmyDYv+B0aOzjwC7Nh3+iKhLD4BQasZxBjzTirjrLib4TMMruWVCkmIWft5fLnoW7Q0gu/yIlRlKw1r/fqVWgVCLezZCJ+v5LJvbUfjdo6ffaqcKoRAgMBAAECgYEAnqE7cErZqPjBkhH0UBUQ9qvjx9dymNN25P4EWz/S4z+Y4BC/ks00FJ6I9wC63/8hMjeJuqLapzHlMPo9mF1uk1e0i89/X8O2OxmJi6lN3rUpUGfEOfa/TPouxIN9N7euFcyaA/F81C00rEyG8zR3S9HDFIUD46V4bw8VcW4BzOkCQQDjtrOt5gB92YxwPnYy9qbQ3sGk+UwS/dOTp4xrDLtpYoiq8TkVgcBm58w07htf0l3QSg4KFgodraDhl7BVfBqPAkEA0njbyKId/PEYsMaRIoRbykMjNuTZMDKFktv9N9F8+k6+BbWQof0e4HJ/dlnrBh34T1kecL8Jy1sxIl5ia1PBXwJAKcAl0YyKKojopuvM4Cs5CrLM7mKHADRpxnjB1h7PfdMDG9R+kuLnU/bMCihd/IOlj7sEN/UyhZ6AENyvB/1pIQJBAJOTKogDJAO3CRjqIdmR9MpdSNO0opSo1/+hQGti976Kd7KJHGB4mq3FmpnhcmlXmkQIuM9VJAjyaAExLNEUaQECQBeyxYIhZVsGpwo7nFAz2O66qOYUN/bH2ilrLQL0w4BKjsB/wsgziajPWxXBT8fw8sq9SGWZUJf2RoXtvQ9YGOU= + """, + rawMessage: "LibP2P RSA Keys!", + encryptedMessage: [ + "algid:encrypt:RSA:raw": "XEknpMZTaFgRf1E4QcpTbZVAea8rMSqe4XSM/UMkcqq5N3XV9nXJk0LKHN/ffr4O5ZHMO84q24bXFMpGJFbm2noBcepVIOoP+V6eLrxWbTadEP0IZGPEq/yvywchDYx9KWE4HVEdjZHCXgGBbsu1TZBj4myvmExaSQi26fKzQnM=", + "algid:encrypt:RSA:PKCS1": "Won/LQrLJHoqCWNJhEw5fqI3gxcCWpIOuHhn428RYgcyYIWEVOpM0hLJd3O+sBujNqYwqlEIOZ8odtZQMStrsqqhz6HyqIAP7LVT1ZGDEEEI26Nth6OS0WGsY4tL1TfaDuZ1fm6c82w7GUzZPfNfv3+2bsckGC/3ZvE6uMr4ybA=" + ], + signedMessages: [ + "algid:sign:RSA:raw": "KIelsfGQa2HB4sIcj/YNwkgNVnv/j7LI3EEReISXbzteEHmF3lolDFB0MVS2Y0yrKtTnk+WHWUQx4iYxOON180tbL6JoDQh+Ut3KucaTpd+Pfue248EvZpu45jFQdXXlqTx9+BgOeyfAT5whxypaE1v98Dj9eo6gsfR1rPvLVvg=", + "algid:sign:RSA:digest-PKCS1v15": "usfkT3z+Uu2mTpu9Qjs5+Q/rtLgy0VQUccI/J5uc6WdpUvscvxCEFTgbMWbXk0FFR9Uj4q3K29rq/oRnBYrBoVBA6nUZUXlaqjR9X+T+BUQxro3rXXAQSImxga02e4r6bIbFSgI86RkQVPYYZssaNr37+XhHwM78SMuGGzJuZSQ=", + "algid:sign:RSA:digest-PKCS1v15:SHA1": "RpTfRiTK8Eey2FQ+IHRQbbrDh+WaEv+ioB3VkpoGTKabbr6VaBc/dP5rTTzlyobsPFZLCyLHfL/VuN20nqWqKc3R+LX81wDCiduqf/Q3UibglUomUrIwB62qxY/3m/xhv6raVM+HDAs+hi6GHBMSU97dtJSrV4UrL0H1y8vg4kk=", + "algid:sign:RSA:digest-PKCS1v15:SHA224": "ZPxZ0pX2C2bH+1+GRe+v7pTXWGuhMp3fORFE9qMFh/o8EBL/+Wh4z6WdnIR1P+TA2FE4g0Pyl1vSv4EMs6lHSyOqJ7lcnq83VVKyrqZXev8TlaYnacU61GRbDfV0xssD5CYodW1hlkB67qjir2UL8HZnZJCALWK89JFRPsCYoUM=", + "algid:sign:RSA:digest-PKCS1v15:SHA256": "NS882+s/9pSMOgIvAxLZzRnO/zIpx0uBqev37LR3ylM+1m5KDw/QKg0H/Md6x60qSWIQ1tgp1GLCTO7qyov2l9B+s2WRFGBoq60zjLVSzz76NOdiXq3LOaNll8oT1t9nKoXo6ZaTKFMFQE5ljk2cM4MyGskHysveAcsULRhDLZg=", + "algid:sign:RSA:digest-PKCS1v15:SHA384": "PIX+JagbtZI093xYwDPLVrNS+j8rKObxwu6JDN9rowD/icSkl70pEQekFbxJVLSVrK1BT/WeoEXxF4h6iIpHmxQuUv9+a2iPKtmWx6rKCiFmMfvP4ssd11JDW5tOfa1mJeaQL1GmUgwlte2lYV8GQGn3ys83EIbJgCM5rKZwgCA=", + "algid:sign:RSA:digest-PKCS1v15:SHA512": "Crw/AtIwICiM5Eex7Sn1pgpOfjDN4sxc7cqCWAKjBzJStrxvCQg8pwnTuE/J3zPrJ/wPJIKXlfdOSOzW1h/VJ32fpoj8UiK1OJt4/psSWJZuzDbqpBm83uFqctI/WdI4f1AgUaCauu+eu04C8viN17ljPHJdTYhsjAOgBCnZnqs=", + "algid:sign:RSA:message-PKCS1v15:SHA1": "qfLYtrDiipLkL4BM3jb6AHq5vABxrEd6hAk4aAhMs88fBtHAuMHpyreozI1DorX8VCpoyOmFm5EviX30tReGur6++YICw0r3ySL5Jx3mn2upu79zPEMiD3PYg25MMQFOq94A6/u7U46rw+DFMqmQR6lO/0JndhOA3/m+n53qGXU=", + "algid:sign:RSA:message-PKCS1v15:SHA224": "hZZqdej0F818bR/j9IgYeufE04jCS3rTOgxDox/gUM1DD89vu7og+dHdGbZlk4ijV+kJO/QRee25nm1v//oihUz4jWTBKdGv50Jiqg3MJMo/qmq44hZEeit0LL0F0yOoAXqlbHhoJweEaSuWFCq424qjFMCV8dK02/3ToQ/O4n8=", + "algid:sign:RSA:message-PKCS1v15:SHA256": "gLpu6xrAzv+zVagq4opnnPkC7LsvsvCUMxUlp62E5o8XV2/4gf6IgJgcbrcmdMszHMGH7IBnJ+9NAL5XwE3GZAbIBLAdTYy4UwmrdOKBDguszmtW5sITWLlFyjjPoDR2NiZcOsJAjhRzBLqFOvjOwHK1S5t0wzYJLYUUMZuc8PE=", + "algid:sign:RSA:message-PKCS1v15:SHA384": "Oh8ruSarZ8IoY5JQgZyckTk77Fw/9K3HYl4JJUv6eqTnJnCK8d7K2IPSfdaNJbzw+CF8rMc5w7EFL3zcgd+7aueHK7ggMrrkMFzrKZMTbx9WooryvcKBhQKggT05/VwaB3nkwyPXFwLpBhMNw6/mE+vG+SZtJNlrAyCuiebeL2Q=", + "algid:sign:RSA:message-PKCS1v15:SHA512": "IED27MAOGl79/9EncYzx+V0nCa5MlsUmj5pAZEHes6X7W8kQaF5Yof3psDsp5QvDiXJNFjoDHGL/y99mCGiw/jRL6bAr0ni3889z4/4zhQPZZ1n9J03yBxmg2KhPL1K9X/yC4EkJQ2rdHTQPwjhoa7H7rIEB5dyiKUWgxBujgD0=" + ] + ) + static let RSA_2048 = Fixture( + keySize: 2048, + publicDER: """ + MIIBCgKCAQEA1T2+nRi/gUmgIbRwECPXzrjHwV1i+SenaIZTK2v76QoTAj9DVTTXbpNJ49goYb+P9PHFubCof+Lf7PXQ5w3370GoB2Ypl200d4NPaymN4hn3nv8th61864Yh96wHDwtSRF+3NpeJa00PKcg4Ghgt5plgyctpzDtllY1zi1MN1kIwCJxoTSy+Z4WtdYIvIcGkVl7SJkNg3ZzGiwpFMPtH6j5R4MNzGgn/Oy7A2x2AQYbndS3qbMr9ftXQEP8eVTxeHnpOffK7C0L0cmMZqlV1uDQaDAXj7R1sMpbNFw+gNSR3clBix2UL4wZAs0bZ3nyEbJVjczzVCxGArbpq2ozFWwIDAQAB + """, + privateDER: """ + MIIEowIBAAKCAQEA1T2+nRi/gUmgIbRwECPXzrjHwV1i+SenaIZTK2v76QoTAj9DVTTXbpNJ49goYb+P9PHFubCof+Lf7PXQ5w3370GoB2Ypl200d4NPaymN4hn3nv8th61864Yh96wHDwtSRF+3NpeJa00PKcg4Ghgt5plgyctpzDtllY1zi1MN1kIwCJxoTSy+Z4WtdYIvIcGkVl7SJkNg3ZzGiwpFMPtH6j5R4MNzGgn/Oy7A2x2AQYbndS3qbMr9ftXQEP8eVTxeHnpOffK7C0L0cmMZqlV1uDQaDAXj7R1sMpbNFw+gNSR3clBix2UL4wZAs0bZ3nyEbJVjczzVCxGArbpq2ozFWwIDAQABAoIBADZVnEs1Mh7EXtwXuPIz39pZtPRtUjnAQ+TbTTfkNPUFTyCkdAizBS20tAAtZOS7RfgY3tPY0qZ7balYXVlycrlxFlqESpa+Cb9mIwdgODnjeff2d2h56TmuHNuZ5taLgPPRG8L6S9aedP2leb4UaSW38TSZ8yRKAjFgMI/Qotbz4SpSY8VE9QODzrGqFVc0HU/M4GrMVqptPAA4OEneb//tCOK/ATrQIsIyBN4Mb+dqCV6tRZKNP9nYRX/yVRI3aD8rAEA4daa4KDelXdTNoVHONTPYTFjAhXEHDldxXS1nIVAVwHaIYGbCgXGveboZLeGcibZVKHCMvHhHraqldykCgYEA+bqgtEcBTgZXrqefJnf375bH2b9zUjYhzI5Il+3fe7k/LwdYNVK/HzUZqKuwO1N6bah2P/9NECrO4IinIAMNAocCfYgfK5l8XmenftA65ek3lzbj2fpVihYgaHfJA5I1LkUbUIbmVv5gQndWZRDcg9Hv7k+q+5AaeP4E5OO6Sp8CgYEA2piOcWtag4zvWkm6ZKvKCRDt380xIvxZqEUkhL4vIY9egjEIdBis23sd9FOlxv570qCp7Q5DWA5ZZFCun9zms1k9HDp60L+kG/xEd1RDdgQwirYkkL8eriIYrGvksB/ywT1pECmj1mcr8h7MNY6efCdjEpUrP2KSYvZlBmF5B8UCgYEA38WYnRIHHEhYp3syBAF6HKlKmVaRWniBHs/cQq93E2FyOYzmQJnOAoPNYzO9Ldvml35dv4jgH/2L9OzefLPfI4Wg+KVR8PqO0/UjxGGIdV3eX1RjJX7IyXx8O8AiUl3f438vM6A9pHQ6AzT2KIfMYR5sVWnz94kv/3z3G7bnxlcCgYBoI8HIuvI2NdBZ3UIVb9oik5QfyOud1UcJaVdKfiiJ/nlx4NY8KP1A2tica7VQpjBrWetaai8fJkbkCaQHuP+Xde4tIpccGBCg3H/psZUqBjjx/HBTHRoKr2e9zPD4D2BhO1ZwQsYxAJnpEU8MPNO4JjOGyNX/roA68VOTxKAaWQKBgAO9iPiQqAff3AtICPI1rMZO+f3kzxD70Dxl2OVRodKcQ13QQXyNfhN/2f5KbEQmAElYrSazaLhYYxTVaSDfkxZUK5xTYSRlAUKqxyTzPQ1f8Cg73GmlpK/cJJSoPorJbYSQj1JXQnfaSh8w4X18KpD/VKMb4IGgygHWAnigTO46 + """, + publicPEM: """ + -----BEGIN PUBLIC KEY----- + MIIBOjANBgkqhkiG9w0BAQEFAAOCAScAMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A + MIIBCgKCAQEA1T2+nRi/gUmgIbRwECPXzrjHwV1i+SenaIZTK2v76QoTAj9DVTTX + bpNJ49goYb+P9PHFubCof+Lf7PXQ5w3370GoB2Ypl200d4NPaymN4hn3nv8th618 + 64Yh96wHDwtSRF+3NpeJa00PKcg4Ghgt5plgyctpzDtllY1zi1MN1kIwCJxoTSy+ + Z4WtdYIvIcGkVl7SJkNg3ZzGiwpFMPtH6j5R4MNzGgn/Oy7A2x2AQYbndS3qbMr9 + ftXQEP8eVTxeHnpOffK7C0L0cmMZqlV1uDQaDAXj7R1sMpbNFw+gNSR3clBix2UL + 4wZAs0bZ3nyEbJVjczzVCxGArbpq2ozFWwIDAQAB + -----END PUBLIC KEY----- + """, + privatePEM: """ + -----BEGIN PRIVATE KEY----- + MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDVPb6dGL+BSaAh + tHAQI9fOuMfBXWL5J6dohlMra/vpChMCP0NVNNduk0nj2Chhv4/08cW5sKh/4t/s + 9dDnDffvQagHZimXbTR3g09rKY3iGfee/y2HrXzrhiH3rAcPC1JEX7c2l4lrTQ8p + yDgaGC3mmWDJy2nMO2WVjXOLUw3WQjAInGhNLL5nha11gi8hwaRWXtImQ2DdnMaL + CkUw+0fqPlHgw3MaCf87LsDbHYBBhud1Lepsyv1+1dAQ/x5VPF4eek598rsLQvRy + YxmqVXW4NBoMBePtHWwyls0XD6A1JHdyUGLHZQvjBkCzRtnefIRslWNzPNULEYCt + umrajMVbAgMBAAECggEANlWcSzUyHsRe3Be48jPf2lm09G1SOcBD5NtNN+Q09QVP + IKR0CLMFLbS0AC1k5LtF+Bje09jSpnttqVhdWXJyuXEWWoRKlr4Jv2YjB2A4OeN5 + 9/Z3aHnpOa4c25nm1ouA89EbwvpL1p50/aV5vhRpJbfxNJnzJEoCMWAwj9Ci1vPh + KlJjxUT1A4POsaoVVzQdT8zgasxWqm08ADg4Sd5v/+0I4r8BOtAiwjIE3gxv52oJ + Xq1Fko0/2dhFf/JVEjdoPysAQDh1prgoN6Vd1M2hUc41M9hMWMCFcQcOV3FdLWch + UBXAdohgZsKBca95uhkt4ZyJtlUocIy8eEetqqV3KQKBgQD5uqC0RwFOBleup58m + d/fvlsfZv3NSNiHMjkiX7d97uT8vB1g1Ur8fNRmoq7A7U3ptqHY//00QKs7giKcg + Aw0ChwJ9iB8rmXxeZ6d+0Drl6TeXNuPZ+lWKFiBod8kDkjUuRRtQhuZW/mBCd1Zl + ENyD0e/uT6r7kBp4/gTk47pKnwKBgQDamI5xa1qDjO9aSbpkq8oJEO3fzTEi/Fmo + RSSEvi8hj16CMQh0GKzbex30U6XG/nvSoKntDkNYDllkUK6f3OazWT0cOnrQv6Qb + /ER3VEN2BDCKtiSQvx6uIhisa+SwH/LBPWkQKaPWZyvyHsw1jp58J2MSlSs/YpJi + 9mUGYXkHxQKBgQDfxZidEgccSFinezIEAXocqUqZVpFaeIEez9xCr3cTYXI5jOZA + mc4Cg81jM70t2+aXfl2/iOAf/Yv07N58s98jhaD4pVHw+o7T9SPEYYh1Xd5fVGMl + fsjJfHw7wCJSXd/jfy8zoD2kdDoDNPYoh8xhHmxVafP3iS//fPcbtufGVwKBgGgj + wci68jY10FndQhVv2iKTlB/I653VRwlpV0p+KIn+eXHg1jwo/UDa2JxrtVCmMGtZ + 61pqLx8mRuQJpAe4/5d17i0ilxwYEKDcf+mxlSoGOPH8cFMdGgqvZ73M8PgPYGE7 + VnBCxjEAmekRTww807gmM4bI1f+ugDrxU5PEoBpZAoGAA72I+JCoB9/cC0gI8jWs + xk75/eTPEPvQPGXY5VGh0pxDXdBBfI1+E3/Z/kpsRCYASVitJrNouFhjFNVpIN+T + FlQrnFNhJGUBQqrHJPM9DV/wKDvcaaWkr9wklKg+islthJCPUldCd9pKHzDhfXwq + kP9UoxvggaDKAdYCeKBM7jo= + -----END PRIVATE KEY----- + """, + encryptedPEM: [:], + encryptionPassword: "", + publicMarshaled: """ + CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVPb6dGL+BSaAhtHAQI9fOuMfBXWL5J6dohlMra/vpChMCP0NVNNduk0nj2Chhv4/08cW5sKh/4t/s9dDnDffvQagHZimXbTR3g09rKY3iGfee/y2HrXzrhiH3rAcPC1JEX7c2l4lrTQ8pyDgaGC3mmWDJy2nMO2WVjXOLUw3WQjAInGhNLL5nha11gi8hwaRWXtImQ2DdnMaLCkUw+0fqPlHgw3MaCf87LsDbHYBBhud1Lepsyv1+1dAQ/x5VPF4eek598rsLQvRyYxmqVXW4NBoMBePtHWwyls0XD6A1JHdyUGLHZQvjBkCzRtnefIRslWNzPNULEYCtumrajMVbAgMBAAE= + """, + privateMarshaled: """ + CAASpwkwggSjAgEAAoIBAQDVPb6dGL+BSaAhtHAQI9fOuMfBXWL5J6dohlMra/vpChMCP0NVNNduk0nj2Chhv4/08cW5sKh/4t/s9dDnDffvQagHZimXbTR3g09rKY3iGfee/y2HrXzrhiH3rAcPC1JEX7c2l4lrTQ8pyDgaGC3mmWDJy2nMO2WVjXOLUw3WQjAInGhNLL5nha11gi8hwaRWXtImQ2DdnMaLCkUw+0fqPlHgw3MaCf87LsDbHYBBhud1Lepsyv1+1dAQ/x5VPF4eek598rsLQvRyYxmqVXW4NBoMBePtHWwyls0XD6A1JHdyUGLHZQvjBkCzRtnefIRslWNzPNULEYCtumrajMVbAgMBAAECggEANlWcSzUyHsRe3Be48jPf2lm09G1SOcBD5NtNN+Q09QVPIKR0CLMFLbS0AC1k5LtF+Bje09jSpnttqVhdWXJyuXEWWoRKlr4Jv2YjB2A4OeN59/Z3aHnpOa4c25nm1ouA89EbwvpL1p50/aV5vhRpJbfxNJnzJEoCMWAwj9Ci1vPhKlJjxUT1A4POsaoVVzQdT8zgasxWqm08ADg4Sd5v/+0I4r8BOtAiwjIE3gxv52oJXq1Fko0/2dhFf/JVEjdoPysAQDh1prgoN6Vd1M2hUc41M9hMWMCFcQcOV3FdLWchUBXAdohgZsKBca95uhkt4ZyJtlUocIy8eEetqqV3KQKBgQD5uqC0RwFOBleup58md/fvlsfZv3NSNiHMjkiX7d97uT8vB1g1Ur8fNRmoq7A7U3ptqHY//00QKs7giKcgAw0ChwJ9iB8rmXxeZ6d+0Drl6TeXNuPZ+lWKFiBod8kDkjUuRRtQhuZW/mBCd1ZlENyD0e/uT6r7kBp4/gTk47pKnwKBgQDamI5xa1qDjO9aSbpkq8oJEO3fzTEi/FmoRSSEvi8hj16CMQh0GKzbex30U6XG/nvSoKntDkNYDllkUK6f3OazWT0cOnrQv6Qb/ER3VEN2BDCKtiSQvx6uIhisa+SwH/LBPWkQKaPWZyvyHsw1jp58J2MSlSs/YpJi9mUGYXkHxQKBgQDfxZidEgccSFinezIEAXocqUqZVpFaeIEez9xCr3cTYXI5jOZAmc4Cg81jM70t2+aXfl2/iOAf/Yv07N58s98jhaD4pVHw+o7T9SPEYYh1Xd5fVGMlfsjJfHw7wCJSXd/jfy8zoD2kdDoDNPYoh8xhHmxVafP3iS//fPcbtufGVwKBgGgjwci68jY10FndQhVv2iKTlB/I653VRwlpV0p+KIn+eXHg1jwo/UDa2JxrtVCmMGtZ61pqLx8mRuQJpAe4/5d17i0ilxwYEKDcf+mxlSoGOPH8cFMdGgqvZ73M8PgPYGE7VnBCxjEAmekRTww807gmM4bI1f+ugDrxU5PEoBpZAoGAA72I+JCoB9/cC0gI8jWsxk75/eTPEPvQPGXY5VGh0pxDXdBBfI1+E3/Z/kpsRCYASVitJrNouFhjFNVpIN+TFlQrnFNhJGUBQqrHJPM9DV/wKDvcaaWkr9wklKg+islthJCPUldCd9pKHzDhfXwqkP9UoxvggaDKAdYCeKBM7jo= + """, + rawMessage: "LibP2P RSA Keys!", + encryptedMessage: [ + "algid:encrypt:RSA:raw": "iTCnmwcO0DT+/X53IyA9kT6JqLt66psHOy4nMa0Jss1JONHvAn1DOFOQWCORVg1pXGghpzgUE1ZdpG8kP22wU3g3Uq9F7vreGzgJNrSSpiOa+C2eqKYBYS9WgXAnLIetoDZSRhrlndc/XJ2wpJk74pVEEl6LGh+iWzUarjrK2Lm2brb1UvOO7q4agJfyPBl/+u0MEMgXkT0DsGzZmsqJWU6s8PPx8ZJiHpa24gFL301sZoiABMpUZubhdANw9Rf7g4uRBJlHFZWc2g5VKCRoAZ0KJT4AaN+ghQe4ttkn1xWYBJ1MjulShNMm8fvf2XxX/3zh7yTKDQmsRAVjHvHezQ==", + "algid:encrypt:RSA:PKCS1": "d68lvqxdu3sxiYncI9KKGkpud+2vsiSmVF/hGvLL20S9lfFbw0seXT/AkRSqk+si7YvLzTfk9vWMP3jALNJtALnuIZT/0tkLJFozgS1Xs+6AfG+f/eplNDYgpkvIPnzWlorItERuAYzgp/8TRQrA0plf07EkR4AQoyy6q9zob+8ppUnp4GHuuuhrf53H1ITqP+1o/gkVdIprSG01ivL2oa1yN6KKwXvN3BPjWWz8K9eNQ20MapmKOEoz6Z7qYgRfX9wh7VNTkKNQrwtkwVcuzIn31ISlgYd7vF0s6GtnjqoJoWELhatWDRBEIspzG4VND8tl0fJkZX5noUYow83BJg==" + ], + signedMessages: [ + "algid:sign:RSA:raw": "Nc1q2PkJEoIpCO8Hpk+fThlQzqSh6UiR4DScA97Bqu0r2q9zZCp72/wsNBDC3JzBt6AafL2rXdDs9/fGCt1P8mH7uwbTHWYgBgx+iuS/pUUNkBD8CQN129VICE/eQq8tiv5qU6fAGZHOFSRtsezJJbX76FLOtdzaXNVeMW5VLaGtTCqYXBqTuuuFZ1IX/Jx0h3D1ZXHq3InSU3RuR5Dc754gZdf4I4pflBLI4He6kjCFlHDBAAiuYD3NznQaLFlp/kpX8uRqWtM8xjhvy9LdTBciWOmx1EiyrDtw+90QoSAyy2Bk6HJchFX9kIMJXk+g8Si1saYiAbMe5INsvdSmZw==", + "algid:sign:RSA:digest-PKCS1v15": "bNZTmxqjUS2N4IVxbCZa81KKX8FeGU6Fg4XKB6MeEHFVRg715d+7++77jbuCKyL4MBWZNVejb5Gb3OA+BqVyGk2PuzdIMnJexpwVmbOMReK+2rDgSMewC8aUNw33VTbIcXvjqmBpHLERPJ2JnDbC/Lyua9h3IAZ1NTosqWCAuReqOhvx6nZtNg9c/Kc5BCUvW02fZDWmxl9Gh3UrQI53uyKayDdYW6oXHPPSy8CwminKMgY827XVQtSHEUcHnvxH9sInmAFTcrgd8/ohE8swdhYzcuesmI9X3vAuAUQ69nPdXQIyf2IKv7bNhbZqj3qXmaeOW4IwJFPnKzCZLHQocQ==", + "algid:sign:RSA:digest-PKCS1v15:SHA1": "oqJ8TYXX/kjSJteyrlEza2sh6CKQ/mvZ/w8bNpIqagnNIZN/rGwFAESEJOVo8/XZ1a+uPsIs7WFJPKuUhaQRe8K2hAkkuWEoaQZ9wTPoMeKrRXImXXO6sx1YVMdAZqlPVkK1nUU+Dm3BuKqfVRPYkk6xjOCqQvLi3kiTkllNROS9wiry+6peLzH8kGJZ4d+pOEM+Yp7Ik6Zho2Qf8dbiCLjmZf4fHdKZEH85Hi0/ZQg27Ublvoruz4P8L43uLM+oqo9G0xL4k1fLnar0krmU9PZhnU0/1j0OF8bbJypzHCgiGAMYgMiAU3yESaxNN5vQTyEPbxjRkrtJ+1pyhZ2ANg==", + "algid:sign:RSA:digest-PKCS1v15:SHA224": "fWnLlUGp8ZVRtisoSzfLmRFqsNK0Pqa/mlHsBcxJ0HxKuruJzkEVKjcelLALyDZIKMUUaPmvKgrnLN7dFNFK1/YUBcMfAr555LeNHh/TVC+j1IUOlxknFSnJDIEc5AjT4GcxvklhD45dDWafC67gb+4M/2A6h70OXun651whOGaVMEztQShqKsHEvLYfFrgjjueHz7tl3J9LjLqKJBC/dsVN1JXLJuyqnHiJOtZ1WwX1foT0bLoAAiFA6f86l75Q1iHdiBSrsNrQI6Aa2JomV8Bb2q0fwuNiMH12x06uh+SWPVCh+oh4bYJvUNXMus49GX+BOwTQZktFqvbqgcDyMA==", + "algid:sign:RSA:digest-PKCS1v15:SHA256": "PqiHMiZWKgJK9Zp2bi4yLdpQgXSn9lrgHHGIv8bbLEi6U9ASlHbCvyYlqk+rqTOkK5+K9O5gIXlq8/MY+fFIb49xmRgYq+LB/MLrBla9eWAfPkX/H2FZfKR0KHHM6IaGYyjhbHLji949B2i9D8TNOmNL7YDP5AT1LrlxL3r0mx6JFZ2BpZd+HugShA+fK0fzsu1NYoiZyhwSFGOuFKf/ejIx/4jtMYX8NiStBRAu/1/zHumKMS0vOPSYzZh1XFmIEsfuF1yXAqRa/QtMFE6rZ9MXhdqeIvNxQrmcVOMpWvOSr3p1YgQW2xZf+TBLIz123rNlt+oS1wtEHH0GyTkgTg==", + "algid:sign:RSA:digest-PKCS1v15:SHA384": "dSokzmcHo8Obo47aOPozp9v2cufcXr2OGRxJl2W/E3o5YcQIps1xNYvyCXw2h3plD91BsWDTE7j4PyYbUmtHtKoDiq2dC6PL07wM2uf8fcXxusIHJOvGv3/lA1wbUik0vLZMO4RPiiBH4yY8OVD9PXCh34yvtxxPorvsOzkEjYadvAwXElBcbXDuOoMTGbAHgaShXsH9Ft+X5rKEtQl0neqyxwr61cTnKIJxxXWlIKT9SDMj2iu0tT6W8BEKLzF9Sl+KuR4sPlFBfJAll38gx/0OM3iy6/avxldIJgKvOFVoMQ0kpSkg/sotXR3ZJtiNVE0W+QYKu0fOSv+q7JwKiw==", + "algid:sign:RSA:digest-PKCS1v15:SHA512": "avuTXRpjQsh1QOR/FFwDp3SOPzo90hCeeVqpUHMhXcdvy1AJmmTL86Y5Gwn3fWWiweFxnXcqfaJ3rQk1bBcLmANP3F29uEajdhecuq+7ma2ieshASsWp/cAq5mg8uIdVEldtcmYO8u5tIqmruOFw2plrgk6ZgKWVPvfSNTcoovZx9DxGNrsfHF+Z1SUpbnDIYVESniDhsfTsv2xtCJjz1100SfKGyKyty9PhPTSDJATJrPjaGmEIcD/nBbiqEf1RhEv7tb9qp8DdkikhYhtDKSIMxLd04dmeyeb412I4uW4gdidv+F+Jqus6DQPmo/Pg8upL3So1A2P006OAgFvH7Q==", + "algid:sign:RSA:message-PKCS1v15:SHA1": "fOdsPPhBGL2MmzaZt5fsH4Ih4FuYeRx1Vse/+F4YeRsMZqNrhOiPyXWqB8j5LS2ggROYVD6J3G4zubYIJ/T5jwqBgftwJ18GxYaA7oWDKbcJVrHK3RsMv0kQkD/Fl+yunf/LMUANomieA/OyAxHGjMXZuT3m//3OruH/j3ck+h47eVY5U6aeNyor8cFXDlo7ljm9xCNpzhrEvbFT0AD7gfv4q4riKiT4cw+h7c9k0a2LyoUAYdS+wDUpG8hJbQ05NScyhCoEB0YquM1qB6R0xgSzEi33kTFMahGQdBlOg1ILmsBf23FfyJxZC4ur6JYEGAB3+WdjDXHE945f+vq3Bw==", + "algid:sign:RSA:message-PKCS1v15:SHA224": "M9xryRG5ScZhfEXt31Lc5hTbwz8Gh1JYC6zWO+yV8skq6FTIFH5KjWCGWgQCXEt8GdHJjKAw8z9qe5cc7qXUuLN6YB+QuKUZs0prqKAru6nLI1dzJ501eHfxQPSBgQKLNTrx4sHfXBUDEvBPOpEgC8Xw8Ye18VrhM7xGoxeUD/8KYh7eG2+pbnDKn1G2+aEJdpvZs5r78dr1cHggSSCaQnD1AjRufnH0vGz/qr8OOxvuZDyLXlQxbASas245VXrth3/Je8xFeOFoWNSGbh/jo6u/mZZh57WeSEBz3+8806Ge70E09yAAC+4Cub/04mBttPstRYFV1DaUjM7MaqyVLg==", + "algid:sign:RSA:message-PKCS1v15:SHA256": "h0bEBt1D3W4VGn4zFNqF4OCdgrGdMWRlZnehKhNiQjhDG4GO8iJlHAtXpoZffHYnC0Sv/TfH1UpDIEAKj/2LG+kH97WFDC0TlBCxh11tRPvfVCs2x1U11zMe9df4j4f5O0iZNic4nPwhvaFTDjmzPXXPepy3XHrknf0w/ocjKhhF2DAQmPu9910N+cOjjq6f2HZ1i7wrmFLqWAMwt8rdoNJZ3VHpPi+PtU5zcE9to8HzG4GaY7X6CHC9eTgnxYdRUa+gNhvjwSr7jngRWD9zvPBoWLBQ5IS6UdzxJi474MojPuKEXBDw4Yj4ZfywlbAoCrcle6UeiaBO8/6gkqudaQ==", + "algid:sign:RSA:message-PKCS1v15:SHA384": "SnFSQhsAzjr7y7lpEfbP/F5gnNu2pNpvQQxjwktfM0i0HACDhIJLKmOpTgRgieo22cYkeP/+HxmGrzlhil7Ie8rOT/yL183X9tSrS8605USsO7AxvdVHLGcggyglc8vTHcPz7lrIhB9nbXVQo3bqMy4hS2tyOxUaZdiBHofpuaDkxer2OtzJGTbzKH3ImwfAQEBuUM6KIf790Z2eiX6bW/T795eyPFwM2TsBKK6U3GmEgm/xFNf5GEeTwEhOa0Antv3DOyu3MCo7u2EjriKrvSs+oJsmWoS28TjtVVhDR09hUcXm9nR0xszZQFHJSwzOAOzm8LW5xtqYuud7Q6niiw==", + "algid:sign:RSA:message-PKCS1v15:SHA512": "AGCa30WjEHkcHkSfRKJ7x4ZbAe+Be1XZ+W4823fke3sS9ya/TIHu29dfNgoPYh3r4C+WHCxsw3NvHNx1lOqZaJke55ftBA6NlV/Cp1e1fXvSBU7x79w4e8CfBG0AX1wbrBw2TexMu5yLkSEfqr8tSsxk7XOwDK9pytJOj9mCVizaTkpwmR70PjrRhsSgKqovwG8fpJD3si/PBiWM2B1DUgSWS4Doa4wl6qPvtHoTeraMnKBiy/K0ODXnCnMwcKo7Ke0pgoSZoXFsyU/ojXuTOTB/rWfVoJHKbAnG+1XwR+Ydxn1db3iFOd5KlNArFkmw+oF+ioKRgkzq5fhBfsZTcw==" + ] + ) + static let RSA_3072 = Fixture( + keySize: 3072, + publicDER: """ + MIIBigKCAYEAzsersX7f5oUheLRaN4CGOWEhJcWJXKqQ+ZrHW8kSqCbMvohtPh7O6/Tjg5smkEM/OE2MvkPBbe04AAg9xPwrcCg/yY8NkHGTe05fAsuxa4a2pU5OP401DH6qwzZLPhGlm0Nrn9cKaDul6iwBi54U79kXj5JveHgb2NGWZqb09xAhdFUFhIqAAzRFtw2JPICdrySudBYfqoTr58EAIb+UNORlT9xuM6Q3LgH8LzkexZV3O9mYAOYgEL4pD5yYHXQL+IkqpnHMCujZ+lXMyfGPlvm3bSUmaEXXZ2DfgmHUz3yTTA7Y/r+U7qi8zAaAtTwbNbxyDP48vurbf6dGE6ojkhYVVvk00oOCMpbPpl0po+I8Kre4HPAqqJzAZg0i1DiTjTy2J3i7e4K45Hp8VObLUVkNcqaOFDh3v1liZdK9jLW6JvMD/f+Zmes8mNF5pTzO5WERKqqdtvI0Ml/VFZFV7NPt9KfW+21ThmR9fXrU6A5Jiiq4pWBtkfBMPlKITMoBAgMBAAE= + """, + privateDER: """ + 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 + """, + publicPEM: """ + -----BEGIN PUBLIC KEY----- + MIIBujANBgkqhkiG9w0BAQEFAAOCAacAMIIBojANBgkqhkiG9w0BAQEFAAOCAY8A + MIIBigKCAYEAzsersX7f5oUheLRaN4CGOWEhJcWJXKqQ+ZrHW8kSqCbMvohtPh7O + 6/Tjg5smkEM/OE2MvkPBbe04AAg9xPwrcCg/yY8NkHGTe05fAsuxa4a2pU5OP401 + DH6qwzZLPhGlm0Nrn9cKaDul6iwBi54U79kXj5JveHgb2NGWZqb09xAhdFUFhIqA + AzRFtw2JPICdrySudBYfqoTr58EAIb+UNORlT9xuM6Q3LgH8LzkexZV3O9mYAOYg + EL4pD5yYHXQL+IkqpnHMCujZ+lXMyfGPlvm3bSUmaEXXZ2DfgmHUz3yTTA7Y/r+U + 7qi8zAaAtTwbNbxyDP48vurbf6dGE6ojkhYVVvk00oOCMpbPpl0po+I8Kre4HPAq + qJzAZg0i1DiTjTy2J3i7e4K45Hp8VObLUVkNcqaOFDh3v1liZdK9jLW6JvMD/f+Z + mes8mNF5pTzO5WERKqqdtvI0Ml/VFZFV7NPt9KfW+21ThmR9fXrU6A5Jiiq4pWBt + kfBMPlKITMoBAgMBAAE= + -----END PUBLIC KEY----- + """, + privatePEM: """ + -----BEGIN PRIVATE KEY----- + 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 + ohNsKDeoGvudaaBatZe6Q5+QJw== + -----END PRIVATE KEY----- + """, + encryptedPEM: [:], + encryptionPassword: "", + publicMarshaled: """ + CAASpgMwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDOx6uxft/mhSF4tFo3gIY5YSElxYlcqpD5msdbyRKoJsy+iG0+Hs7r9OODmyaQQz84TYy+Q8Ft7TgACD3E/CtwKD/Jjw2QcZN7Tl8Cy7FrhralTk4/jTUMfqrDNks+EaWbQ2uf1wpoO6XqLAGLnhTv2RePkm94eBvY0ZZmpvT3ECF0VQWEioADNEW3DYk8gJ2vJK50Fh+qhOvnwQAhv5Q05GVP3G4zpDcuAfwvOR7FlXc72ZgA5iAQvikPnJgddAv4iSqmccwK6Nn6VczJ8Y+W+bdtJSZoRddnYN+CYdTPfJNMDtj+v5TuqLzMBoC1PBs1vHIM/jy+6tt/p0YTqiOSFhVW+TTSg4Iyls+mXSmj4jwqt7gc8CqonMBmDSLUOJONPLYneLt7grjkenxU5stRWQ1ypo4UOHe/WWJl0r2Mtbom8wP9/5mZ6zyY0XmlPM7lYREqqp228jQyX9UVkVXs0+30p9b7bVOGZH19etToDkmKKrilYG2R8Ew+UohMygECAwEAAQ== + """, + privateMarshaled: """ + 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 + """, + rawMessage: "LibP2P RSA Keys!", + encryptedMessage: [ + "algid:encrypt:RSA:raw": "wlT1qJE2EofoTNS/Tj/A98ehqJLwVVENKQ/ytQMV2mbzjkFs/kVBMtATmYuyFEYBTkZ59nlqRcrOcPew03A6dk07Sir2HdG65dsDmfOCuW1iZcnhBMNkMKIk38YwtRyPkrjthSh5II0UowEUE2D85L4+Ygf7bWk/7WJRxVhmFUd99inWMpodv05YvQJtyH7TzyjUEipjon37d5Aq2DfxUlRQJ65+ZHk1yakT+qdc+/TvjH7SCgcMHyB36gAOwyer/Odp5spofIl0//8iCnKK9zqqrskjfEEoiYkYpNrs1lrrzWE/kCXcxZ14nCEqBBYG4Y5P3U9NL85NwPaB93rxWyenJtJ0kDcBXX3Sa6BENLkwc33Ma2wMsKXxLWSHP9xsIOlHjeW/eR6IbFuhgDzojAqAwnKN5APZMieANToaYVzpgBs/QrUIVLMNi0Ua1xjpQX9xmxNIClzzHa8Uj22lDbs+hpSJIX+5EgNe+INlBiQRsQHJhFUuTkbZeVvfhQOx", + "algid:encrypt:RSA:PKCS1": "FQPy8WaNWSZYECiv4afrteLxH9s0p2MMSRxpYjEg2y6wGfwQLjhikZSnt+guHQmq1q3Enj0INVzAZ0kiEYywbycfYL8GAXZIsDE8bmQBqDX/Fcib17wBnLCm4GmFNaf7j6PS6itYrGfe6qulwxL7MzB8IhZdkPz9vvdBoC2oMo58wUHPlFljoADu+lIH92/0s2JPMEgNKu0qlVBmx2TnjuHaJBgXThCcrErDFpAxqBAGxKVhRMJuAO3WtHCQBLUWRSxzfYR6sygCcBrHhLV7foUiNa6aU3Uj0nr0vJXmk89JumeYmvkk/BT0uYFf/UdBtQZTt6fvFlcTX+AeU12W1Ez2PexfsiHLqfibP/nGE1UrleSpx9EarT73lahPhOHGCXosgxEjwT+SPLf8ZKDE8M+1GYOU/03A9btjoB8guBw+nfbdhcKJpHRA7Hgd/UzKdKRvaORtIaA80dseQK7cSsE3laaRncn0A+Z+UMpBaYqH2IBdENOx9xp8StFz77Iq" + ], + signedMessages: [ + "algid:sign:RSA:raw": "SIqqOlao51DQeCxN+Od+ENTmRFIIQLMs8WmQz8jJ4OScmDPSvV/EGGNk37JqQdR3ydN7Cp3Nb0YECWIkQPzaciuRR3jItfesQHx4pucv+4jd2ir2Et9NbzhTnpowHZ8Ui7Pb2Yea9RAITkf8+dTvmYWiJLvUuGHaXz1KkB1TMSbMcI2ElfsCYRN6ofs18WhcifSL3OI+4jTdK8V38JEYJZRlmuEQ9IXLE6yWJ3+0ZBDNZyQ+P3N7tNvV0AmlBqt0euD+EK36TvNpXVLS61nYMD44d2vc7OpTbkCjuzLVmMx9gF9cIhCYud2WtXU9z640T9YgD4zVGBAGMMsHOK6RF7yR1G0W8itmfJp0EdShVFh0p3Gfh2+FSdIFKV6xZdQ9Qlyd1NzFLNgK7299wBjPY8VU4++PhMbXipMYiA0xUkmmiXpbneLoPDfaIRpsKC72NGcTC5uo47nf6bJ3mH32IX7TuS31tPRjCxrC2c7EJEHUZdjSPGiHaFlDsnMSzgtj", + "algid:sign:RSA:digest-PKCS1v15": "ibLBssBCod+XN4yvqtopucRVd7j7WYBuAc6m6z61B0WclE1BPFAezPz+Mrr7QipKfSXYvH+kTjmyEJx+j+egdJ/w6WjIOibmLyBgQ1/936iR2O8OALREdXJLQ/RTVJ2ZEQOrbKaCKXRcSo34oHrv4IiagEAaDB243omlT4zlNSaaKSMhvb4RiujzUUxl//r/u4OyuDFSxhM5UchizbsdH3w72pjOJInGFuAfrIRXF0yYKgIFpsGXh77go7K6imU0I6ZwFSUeVDJYBos5+3eWAq2kboAYoyQscpyyfyfxzwXooO70y3OqjHDt64IMjYpqQpGFXBpbp97xNSiYO+44aYktbvhT+LqL+g7EcG4qgF+0D4eWbJAcpKLq2LCSAwnm9bieMDuRfcdoZa/REi9XLAfcXbjQ5q4UzOr0KUejU6U4Mkv/9tdg/LUufzNtcukh/+ADv3p0+42iatrXMuEj7yPpdf+wKNDusscEkGL0kOldNYyODgI/GEXwPWLi/rAJ", + "algid:sign:RSA:digest-PKCS1v15:SHA1": "ww9LTKFkuIjZWLeEKEx6Q2cQ3L5em3vmjj54yvIi+P4OXb4MZdq+Xdvyr6lm5M0WQ4Q36T/Sl4qtvMEItIIplNmQ4ah8/H45+e2b6RYcDlR8pWIMXo9AnzGsM6WIFDsS5xcqLNEB+u1OC1Ukb0BanEdmG3FgzIZrCB3oaHIyzmKeRkimcSqjevLfJsxeJ6mpxsYlYKynEhCmP0GIlp07+oaPEVDZCCcIbxLS6/gNgywiWsSxS9DaJhQRU0EqNMBpQWK0vjxwd9guFdcXAw23LQbA2KxLbqeaEY0j47eOQ728f1Qi5Me5Drdh5eMxDFc6tw6zBCqSGPVG84JM6yeckOXXQrYTyTRRJZmo6msQCi9SQBgxKDEyVD5XqPuI/mSuiwcAHHGdD+OBTNpCKAahnq6CzAywbR5jWNTDKDBeJtCPLRaQUg/c0JhvWZnKbZhBF/fI7/UQjkcRZsAFP/D03JZ6JhynVIWYIHC0OpohdyeknyjDe3CyZBZQpIxo9BRw", + "algid:sign:RSA:digest-PKCS1v15:SHA224": "P22CtZun4BVEbTngy469qiw19SEYSnnhMcEq/msHZioEGXkqo4n1/0pUT0YbPQ+VSZg/KN8Xuqi/HL09BRqbU07k7Sx31pr/Lh5TdII87DGg6MV59u0UpzzA9zINyXgbNCc29d78RkZACLrULZXVeg/8+iDmfG+QuEvITBjCjJ2Uc8gjRUIJHpKulLN06oKNINjbJ7EZB6mTdXpWS4MK+VH2quTRhg+VBK9I5UbCwXM32lSaUbDr9iylUHEJTjbsfH+W9eus3ywTo+/I5Ve2hgSZLg4SkzSL9JxGgyUECuxEoVU1uImXjgJDZ0VKO9iZEJ4qhwkPpQP60ew5bXQAPlu1PsVCs1R+1mlPZGXr+YO7WHfs2ZgJ1pU/Z/mY8tAStcIaPCWiwiU/tjul0eTX5JVzbRN8vRzAGAtf8LONEjbGV5OfQPsfCwHoJFkSBoZobHasTiHUpNW3Qnmz4XhOaImxte+oPsL4GOq4ORvRvn5Pe9mg92pZ4uWR/2Ls8kzf", + "algid:sign:RSA:digest-PKCS1v15:SHA256": "LO/q9HjRLDD/t94BSm491M3zC2oRai1MT97CtPZenJ2dI+dRTmoebv7C8LWoKQDVXnmZX3xjhCQHhW8nmYabfxYD1SZuFDrZE5hvQ5X993w8DbN8kXrr7vA/+19zZMAxcKdx33wtokCH+Q3KWVgr09X9BjAIWtNx1w4guMFKOwHurvBVS2KItjgZ7JkdZ5jX5raQVxj/K3c3YifMhlbw0M9CORr93KAYfmYohY3XO70NVSpUPtwJ5UOGj9aUrtf76UCGaIzqznn9R+mPnQLzvh2NXFbJPWI7Ry7QVWaP114oAXSq7LiWGRRtb5nkWe3fX5afJ3uF5iz2FpvGLmGbCHyXuY4l1SflxgEz8CE38c69lxJpaVi46wlENoCvy1hctNVkJj24zzRjvMP/k+v9KN7fKoL8lG86yCJQPQdkMcj5n3z6/ib5W01+5/DmQVP/SdVhndqiem2NX6hq22y/TGPUEsU2a/oRI8/iJVv0IMy1IkWWCiXjwqgOvuUF0ErF", + "algid:sign:RSA:digest-PKCS1v15:SHA384": "o6QwBqhODSTZ/S6QjzWzENb9oGmU2C9MFAJ1BVnU0rstl301EjuRbiKqfQKGdUiHDICrcQF1Yo8hntlIPnRlUSRWTjGfSLSSqox8D/PGzNyoF4wMX0fvrgMfjfDgDddMwTaD5cx5WVTA/c/aKvo+hFhMAGt2EsUiEq1QUgOHoxB4jIz/PjuP1b4BTRnMLe7QHNXDqM2x1g+Nqpqkk6GhE1kLDrZofBoP5Kc37oK0BGlZgnb+5mxQ8+fOZxacZiAdpkcpvhhWfk79OtlQfi5ayeE53cnUBYRKysIc/pqhNdAwxXbLUKGcOieJtkYZ/Ei5LY7lBh//11MX6oxSNV0mdmy+zmFY0QK504Xph1ffvJ9mtYUSscfd/cILbYPxTzguHkxn2DxNauALEvjg2LO3JJ7bP9R8mc0m4bzgHk24iuGIKnVQW3riHeuyhFb6BKsXKKDPW4xgMhb2rANkwIcC78n6yzwVgzUfPCdiXPnpCMwGcRgyQZ+7EXsNM6faofX/", + "algid:sign:RSA:digest-PKCS1v15:SHA512": "Z0Hi9LVrlBt17g9QFp+kAFBVAmshIz28RQl0HNugrIyAN0uWs9JYmchR6IyZ45J1zE2jI3Utb5wAJoqha1Ej6oVN0GTTuA1qdmdpHNnbQbCrQryMPskSAeX11usd/1aPsWNtQOj052HylkStkV9Wsp3pRMpdKjtSj9Mgjl9JAPlWQlbxX6a5+ScjVfQCMpt9o931ptg3zD0jPLeAsRsrLVJydofjwUMEkS2djRdzIMQKGgvt2xvyYDxlV27WrdAlqpOC2WGYY2tkSAP7FAxHS8OluvZ6fA3+rZmag6EajxRLU9jmgwE83YfndS77LgjuVrNM3J4Gwx4bjqLVl2ploEYL2wLjm8I120wRKwRxXI6E1UfiwCjffLetg67GIBc9kmPtZPAcWGIxaW8FKvX4Ir4sNYkuMGyfMXyzChUtmpJGmwY9dstEw34p7jPIdt+Q0NNbSbYo36lwLSTAW1XKUE41ix7ufC8S095d2XKgPsc2f77NUXcMgXQGW3ly8H5g", + "algid:sign:RSA:message-PKCS1v15:SHA1": "Tn/qW8AnjQJGGGHZRWCL6BrEzl+eG03E7qKh3lsngDPmqCMJBtcKk4rjTAWBNok+ldr1WNwJSYZvFk8udQ9LPxd96nkWJYio9+MG8y+ZY5nkrjDacWRELlnchHv2Cwr3gK7qFGT3EqVEuOAarVGxIBO/oOZmajawk3mBX3v1nEKPc94BT+qIsFTOJ/T+ATnksJVQOC/uw0ON+CsmDbhrpMrwccExUKVqUZ4EUusHwDyQAyU9tIIBNSGVyljGHhzpcWWQxClixvoMDD6SL6XrhdxoyzjONkqop+/Vw7jUogsLd00FjyhgcnahcXwFVQ71nkD22aSrPdXAp1LZCsQE3tUZcqc3eU2R3TM8JSsrovqwSYK33B/5dav84qBBCVqPEjjPcCTLgP/W5jzMX+3CTjYnRswMGhmHCXMNsEt5Sk23g6AlXUma+uGs3BlE4ChsZ9dGgoHQB4LroUcjUpraAXoG2M/jbX3si4l2MJqoVBulkGVC6TrcCCLfQMqI7wDR", + "algid:sign:RSA:message-PKCS1v15:SHA224": "WT1S9NHq6TAPaSCn8d+h0PjS1aOHC39h/8iZBBWVK8nCYOWkjmBBwt3yFrZTLbJdoNZsf+86bbGBFPvMta+rZ7dkDfWHVA4Ufh9NfG4k/Urw0cx0yEw7uTgieZZOGVVMt5eQmXEZMjlWtxsbThJIugRSCVbKILUkv9Ja+sLLg4vncLgQQqpJ/aDXG3gCiw69BQtHzbYKqaN3AAVD1/jfQjFYD5o/zajFbh9WWZ7ULkne+xK/8fh0k106WdQM5Gh5qazBxI9d3knMqGZuXiTZczZrfRwzKhkZgb9BqTvGQWtvt8ZbMw8trqKcTCovZFR/EAT21++kdJBoDZCIb1o8wCEPFddVjhx/B+HhmYG0UkQWJvNSvJsOAeGO7/PKg0J8X5vt26UUs9nLWEZ8x7gHwT21TSFeKBeNJ+p+Q6bitEPYMTADdpMXQfFdJL4HdTaIOYJ5qWaPcuMAID80uBrWrQXsi225Uk0yBas2qDOY23TWxI5v7D9JXjqA5KqfeKde", + "algid:sign:RSA:message-PKCS1v15:SHA256": "r47sYLdGPYjUcxDR9NvfVyx14oihkCzZ3HmrvRInvKZb88DEe+tbcCDhm1v8SvZkjyRIabDzK2UbQzfmnDWGFHlrfWpjQ7uNZY5vYQkiEhc/qun0a1/eAqN23FgDMgBXxUZMZTkN6mKmdmvp19p6mGamngTAFfni6MBO9VshOKE1oRk34V7T4NhdmmqjyGTcrHJKpP5JvVTfKnQidoojqzwD1tKQGwl056BQ93qzXjrqfxvlVRogN5AsT8zV+b0cPDl4QJKr8Oj66ZYdjVOG5lk2b4UzOXo+Oy4dbIcitd3s2yIzkVasNA2L88VE+P7W/lBXEWOTHqYku4SmdD8YFEHp5F1iqjKi/cZY2BmNevtcdrNszu03BA0MnxksIysFV71VNossaVXfT/i+ckzNwGLf+WIwzg15yCOIJt12fDuTNZzFRfT0tDURVDNuDov8aRq0PA7wQLs00plOgAUBZ3XZS0gZOS8hB4UcacNQewYqbqPrkaiVlTE89JE+sgki", + "algid:sign:RSA:message-PKCS1v15:SHA384": "kxkBL/754HXu4A7GsVcs23uk/qj4sR2Y8vVLKJD6Aa7SE1gCbTeQN1MBcYF0nmNq1IJm+8hsRBKpXsR6q8dU6rPXI2RiqkGyS+qEy5f87T4MMqz7SdVqWxbL0n/rzRiGwGEhAyxYqlheDIVzMEhLlc2vHP4C/fyWWdnlVjOeboBiL3iChXiIHt8y1IsOHOs3pHKFeHS+DCD6zK48m1NolcQaJLcvwEme6JJx3eZNSnZR/bOaZTygpJn48PMC35EbG5eOBc2a9eDq2uX8mFN1e0tS+EbdQX4wYXHfJNaB/kiBA8Z5vTDnPoslKBIkLwlcvXpz7i0O0KyTbUloZGffRZqxQTKb+eJuRKzovj9FgoIuxnjnE7+HcFhNOKFrBi/mqY2oC2Hx1aPMISIJ+Ai038dkOS6otlfnkP6m043cRofNlorM0d9CSuUYMLQwjonAHIW3a10K9RvHdZcAbPHXIeUuWhmTLk6f0I2MoOVrcY+ZDhhsKgVVEHUlibfQ7MZ/", + "algid:sign:RSA:message-PKCS1v15:SHA512": "N0MY0xXY9sj4gpvniGaD/mErLhtYMzUcseBVBzMwSz1FUFymZp0z2JmmjV/gVGewKY8DzGgkVXS0vpj7tJL3F+x2KOlz0hUhAn7K/G/SLwd3f9acMIq7NdxeEh8y+nlB/BwzRea2hnb4sPq0/TqlcNrsipgliBD14l7vgdqTgmiM4WRhA2h93CARR6mcoRiU1xSkjGEVKaHdeKRFCe43kRY/dmpVBW0Vva7MS+lPT3RGHY8rAzlbSCq/fK037ljMsByqv2fVwoIOLC9G/EN8liX0P5Xo1BjuqP6PSUZOw+8d4TbD1KtesnNlQH94usoQI/XCNtQSzOiQDvygA1fEGjnqj/+z4PGyjcot6r1VeO5noAsZI/JmhdlK418q6FsAH78oeGlMYLguhGErwu4pRUJKUb5tolQCklMC3wofSncvxiyAje4RqWJltbY2pddko9qNs7Efx/oNGZfBZ8S9b1vzYm6wcd1OMUQzymqf9JU9orNL8GyASk28/46vWOx1" + ] + ) + static let RSA_4096 = Fixture( + keySize: 4096, + publicDER: """ + MIICCgKCAgEA7UWD2/7gw3e328OzBLjcfz4LEgg57GMYX8kliiVv1MvIh265F+wGbBmlCKM25BFA6Fkjk6XGTIFIk1CyLAluVNCDbcDuKiwgAFRc+DmjBBXKAKUtBWY4LtMtEoqJnayIfukho0wrIIgspN8fzmJIVPmU2e5aptDa/6y/1PUQSGnqm+PGX9/QlQ+0fop9YonlpKgxLYkoszEr96nvEOuM4otAwGCiCgdygQTzrU1xXyK2S7iqh2Vi2B2Cjmp2nGmTAMUnrML0A3Ld6Azc5qVMF59n4icyzc1RmLl9imjUfhWzfg9lOaq883WVdlRK6rg1nxuhqV06sS+W1QpH288rvr3JQlM43LOArQHtLjABJVyXhkXVeZzAmL6hYw44AC71NFLzbGltHkaedQMXMBO81HPJouVGyQlekYevG+efjrQ1oUA7BlZywoqF61IpULpLbLUmgbf+P36TxyFvXhJS1tbWVQ7D+a4cuZ6M+p3hlYqostUbcytTUdTr3G3uBedq+SnSiObx5uQUS9B2fYU/k3C6UC/yhasXAR5hvFojed8G2g86njzq14VIKofMOsMG0QkpBrO9bdlMfT43ZjYEs2SuUVnem/8UMv9Q5TLtjwLDmgXXtjocascuNpIWTsUfaiKRiwey3o1iK9axqvvOFvYQuXFXj8GH6aKdKWejpd8CAwEAAQ== + """, + privateDER: """ + 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 + """, + publicPEM: """ + -----BEGIN PUBLIC KEY----- + MIICOjANBgkqhkiG9w0BAQEFAAOCAicAMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A + MIICCgKCAgEA7UWD2/7gw3e328OzBLjcfz4LEgg57GMYX8kliiVv1MvIh265F+wG + bBmlCKM25BFA6Fkjk6XGTIFIk1CyLAluVNCDbcDuKiwgAFRc+DmjBBXKAKUtBWY4 + LtMtEoqJnayIfukho0wrIIgspN8fzmJIVPmU2e5aptDa/6y/1PUQSGnqm+PGX9/Q + lQ+0fop9YonlpKgxLYkoszEr96nvEOuM4otAwGCiCgdygQTzrU1xXyK2S7iqh2Vi + 2B2Cjmp2nGmTAMUnrML0A3Ld6Azc5qVMF59n4icyzc1RmLl9imjUfhWzfg9lOaq8 + 83WVdlRK6rg1nxuhqV06sS+W1QpH288rvr3JQlM43LOArQHtLjABJVyXhkXVeZzA + mL6hYw44AC71NFLzbGltHkaedQMXMBO81HPJouVGyQlekYevG+efjrQ1oUA7BlZy + woqF61IpULpLbLUmgbf+P36TxyFvXhJS1tbWVQ7D+a4cuZ6M+p3hlYqostUbcytT + UdTr3G3uBedq+SnSiObx5uQUS9B2fYU/k3C6UC/yhasXAR5hvFojed8G2g86njzq + 14VIKofMOsMG0QkpBrO9bdlMfT43ZjYEs2SuUVnem/8UMv9Q5TLtjwLDmgXXtjoc + ascuNpIWTsUfaiKRiwey3o1iK9axqvvOFvYQuXFXj8GH6aKdKWejpd8CAwEAAQ== + -----END PUBLIC KEY----- + """, + privatePEM: """ + -----BEGIN PRIVATE KEY----- + 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 + YMm4CrozLBthDCm6ApV8muQxGMZOVQ== + -----END PRIVATE KEY----- + """, + encryptedPEM: [:], + encryptionPassword: "", + publicMarshaled: """ + CAASpgQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDtRYPb/uDDd7fbw7MEuNx/PgsSCDnsYxhfySWKJW/Uy8iHbrkX7AZsGaUIozbkEUDoWSOTpcZMgUiTULIsCW5U0INtwO4qLCAAVFz4OaMEFcoApS0FZjgu0y0SiomdrIh+6SGjTCsgiCyk3x/OYkhU+ZTZ7lqm0Nr/rL/U9RBIaeqb48Zf39CVD7R+in1iieWkqDEtiSizMSv3qe8Q64zii0DAYKIKB3KBBPOtTXFfIrZLuKqHZWLYHYKOanacaZMAxSeswvQDct3oDNzmpUwXn2fiJzLNzVGYuX2KaNR+FbN+D2U5qrzzdZV2VErquDWfG6GpXTqxL5bVCkfbzyu+vclCUzjcs4CtAe0uMAElXJeGRdV5nMCYvqFjDjgALvU0UvNsaW0eRp51AxcwE7zUc8mi5UbJCV6Rh68b55+OtDWhQDsGVnLCioXrUilQuktstSaBt/4/fpPHIW9eElLW1tZVDsP5rhy5noz6neGViqiy1RtzK1NR1Ovcbe4F52r5KdKI5vHm5BRL0HZ9hT+TcLpQL/KFqxcBHmG8WiN53wbaDzqePOrXhUgqh8w6wwbRCSkGs71t2Ux9PjdmNgSzZK5RWd6b/xQy/1DlMu2PAsOaBde2Ohxqxy42khZOxR9qIpGLB7LejWIr1rGq+84W9hC5cVePwYfpop0pZ6Ol3wIDAQAB + """, + privateMarshaled: """ + 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 + """, + rawMessage: "LibP2P RSA Keys!", + encryptedMessage: [ + "algid:encrypt:RSA:raw": "FSE6NautB+EYA28dmfFGJfq7LMeZ+8rMR401Ai2J+s3ruk8xEzETtioQRkAUN2rxJJ9I37uLG62sH1GRYqWVWeyC9Aqdd9XOEj0bmerHsHHiFaEuKneM1rpkYkujyQHJNl/DbAp4LRvgVrVbwOtc/9DBO5PIyyShfv8UeVeA/y37KnSk11mWNKWGn/qBir91eQNEhJSqvnyvdvs0WdDuQsMNHyYvcxvmA4BTmPSAIN7839yuOX27npCmajNbjTCxvf8s5ZIyGRBo5UYbbGM4BfYcR2ogmhIQ0YyikrlDiMj9Q8fw8ih6bg7iLnWbl+N8qM7Oz84Z1K41LWUx0oQ4TLkvkXPdCL0TiR7jkCU3s2OT2jPkfMq07s8A3NosDy5HTJC01JflfsMr0K1UrSeMDWmWLbRm4dfh2gGx7nicQ8/mlUoL5p+wWRc63u2ZfTB+aR+ueic5ie1bL+eBIsYcbDOmoMNuW3mMEK6efpNxraN3KuTLIcM8jsYACqm4Ry/podKLY9p6s7iwoko3duL4DakUCMnlP83AOdixDYFc3LO+s9Hy6TkPN+feK+lkTgP1QyG9frlH8Ox6NU8iaHF+Xe2I5Z0RCWxQgFlYiwBYS31mM8yqo3+mONDSZtFBUoPiShGT2wZcBEXDlvHOYQ+Lx/3xqSov+DBs4/a2Wujaetw=", + "algid:encrypt:RSA:PKCS1": "DyDJazmOoNG97+Fe7sScsaHjI9K0EzmikpTqhYIGPAM+RdqAnC2lFqesLj0VLZwd4ayFok9bmMabjhTsh3HdQxoJ12VZN8NZtmF+6D7zPQaZrqMqZD8iuRupVPIT3QGWKXXOBfrvdWavCqEmS7dEdlg+A7PS+jEauuLN/AtvvrJIDzRUWp37A4lGfTjg2qPFACL8gJ+C9Nma3aOeqv/Qi+t9YGc5CRuimFqy2d2T5ingWIV4eVrmZKGSmHaDZDmb3U1CwFVQNvG/cv2DPM/WflMqz9vDxTUWTofCKPas4lYyXgIeR8Xgluhq+xFHNNb8za4ILXSJ9WZEXJTJMo1G0/ihxYbjGk9yLJA0JORw15V7fVKTDk9qbtcn8aT+JTKPX0tBBaWfqgB3GO5a3oqGs/UTLDK60Ev7UAycHlgBxxAJ512HwuFXgmcQnCLBW/EWs6w2ugHRasn6WBjI7utbPk1E0nBfudZpUnmRyAGtGIT6vOEyDnfzUEBeqgGbZ2WY38z6NqQKVz9IKXIvR7twPQL4IDg/IeY6ZkxB5x1gnMNf1ppO9LonamucH3hy57rHUZ4GDpenY1sTZEw4tCWXraOanhYVtPXEjblATV5/IHv53qNz38gmOQ9Di1Ib8hbxonSQnS2IMpmiUkgvaUhTn46CJynlk47T5UttVKupdlU=" + ], + signedMessages: [ + "algid:sign:RSA:raw": "SGskSQzPDN9KQMTOCXBMvh17y31w7KnXiVoOFyx9+HREa4zieP1N0Rwrygp2dnBtLl+1UqSd7wfthx9xy4JVVOiWUslxaYfF0MDP+OMsh34CIrt7MUmBL2waXk/5Ecuz6ijojjy86IO8TPfsiWgBeLa4GHrwtI73EP4NW8Di6lpoLcD9rzFklldu7kEvszOqfAvgLEwMGPxMLjQ+pzLePNmdO0uoOqdEfnkVA3dcFOW62LwHTGn6JaQsiL/98afjIscVViWDD2Lr6ydfZfF5Rvf7YXFlwPMqitmSZuNI0pXcJxkWBMzZ4/4a3uHw2WbVK1b5ZCrGgCdc1CN6XPG33aL4PN6G4+UMwJGmQ9JkyB3Ecma18BTERJCgJY1jng277alqyNKpuZIT6DrwdMleJQt3VvVgSM1sJZcOvEv20R9rze0jphk7zWhPO70B85Lr7GQns/8qL+a8iFAbV9Nra8mA+T7vsNr0t0UXOSjnJPMjoR7f24Bt1FzH+X37q6HigirUrjvCWK2tNcRqF5Le1TL+mHinVzdUouJ/X/6u8oaqgfwuDi9aGncwSxkSkyycPQ14x1T1imEbRQO+iCr0GHyyPgVEDNk5ycy77wPegh4R3EY09nBTa+G9AhYZHq5dWylcfObwsXZMss6i6GN3FA14zgA2KixXEzRG8ZEi6ic=", + "algid:sign:RSA:digest-PKCS1v15": "DyKll2Qr2pe+XOII07+RBij4Gf5MXWSbVKjoH/C9IiGLySUS4V3kJNBukEtnVKsAj7DiA/oPgZmMKmy2xakMQF7OcSQtq8sUwxUQDjI1J7WU81DrRUlT5rW/3Vpf/fwS2zGmzV7gN2S5f55VT4KpvcfFJZwVKzD/cMXTKkLOiBo/kvIg9+KG/4XWWHjzHyJlMxEa3I7g0epz50VuBlTLKhRnmbVzdae4kftbqM82luoyV2ES7d97I3oAtZjhcelCiTzLxEFfkbAh9mPJB9lDB1yRAdEwKmSM6/pG1wD2jjdxgkxulnQmUaYdEs9WQ113nTqF48YRiLKr3jTFB8CvCEnDtrXFK6pLSZZMJGne3l2ZIef7YDeDC5102k8Vy9/zjJ9oLhEbhUVurUA7QG9rx/rarMYTVmEOOzd7pG36FSs8PLcV/1rpnd3IbYFHfIc8bMGoSwGnE0hvHDaF3v5FnRESIK02yCIXppRKnKVMcSTcahCn021QWTW9j9u0hvAj6+G0uGMY0C/RxNV/SZ1tOfuaja54xoY0O3YhRNwq11PNw3eWPkGxQdOBZym+qmBE5HzyhscIXM3dVTBQny9CcOtD3AZUmcjNKGXtmxl+IfMRJOAtvN+GONa9O9pAElBY8wIBP9+RRB0DCBKPY111zwDGPDFJZasqNrNslphUhCI=", + "algid:sign:RSA:digest-PKCS1v15:SHA1": "ecoYyYxSvdfmSEJ6UiPI6oZjZ/SINTd2irgCsX8thIXXbFjLkdRm2owfBdke3l1LnSiqB/8WT9B5HeDdSdYXwNNvEucIlWi4vlKb7hv+hcV67jXvjAWxnCetui1xYZYHniwX/2medzlP0aHHXngQEWoPdLfiijJbNnAAWurAJUsl4aik6MAkQoqiY/myiihtLPuTLcU6Is1f7fdpcvRdrnamCklWi61S2/E2RIRJ/fIKKflNLR5plhE369/9F9cxCi8egomSC2qw0Uz02AexmQ01Uj6XRYdBCNyR3mtgozzZKIQPjm5U8pKqmOR5rvNU2idKnalbm7rwRYFvjuQ+4SEWI7f3YlLPeR8gMKF5sousID0qEwV6c7Hl3K5Tb8zrv6fYUiPZLVoQNvjg3KJynjAB7ciYuEGU7BZj74KUkMVxi6JLyyxGEHxXEoN2uWFwGnaBa+xjknL0TJ1P+4G6kQQLk5HsQe/cEa5ZkFJYQdQA8Sh/tB3BFrjKCO7OYolTwAAS9krsi6wSSGALDEH8dHLb9D6mZyNBARXw/yCoyfdKgtis46NkQS+pHOcy59N9l9WDmaP8ZRDBo+RjyIbgKaxqnZvKSihmMLOdUlbg7ZYWAHJPDCLpyYZwljwuJluP0NgxDGEBUzAASo+RKUCVh040mwRqpeNJ7vKfs0HKkig=", + "algid:sign:RSA:digest-PKCS1v15:SHA224": "TuBls8VjkpTCa8oJHW8/K/X+Niqn7nNx4Xk5TK4P2KxrZLGEwEaVvPkk4XF4JAkbVBa/g6123IIFHOXpe+Ut2S9KLrmTx3uUULM9yXVCHhHqTsqC+5doG0zr/fQmvxKHQbAxhzvmBTzdGqIQIkMuiilHFLZdm2zYiLVSwEC0EHq/RtvplGLMiiViS8jrfJlhblW8r+fnzti/jzD22oh7u6QO2uzI6bWlV5j3W5vKETPJnSq0TRDdrRVUAOag0S209dNHlZd+TIYrLAWRqnAzvTVRcp4v+UpOp0yPTxn6YSOgbOX1wL/xmwVsQc3RweLL+mr91F35iWhR+JMQr++vR1xLLzvoU/jFYfQ3OlcZZ6yt5hLorzEKTDryqiLcBqYe0atFGPROQqhD3X5vMoOvOLSa3wRKwABKgqUzpfWVqswgo4T5GpYJkU6yd74quzhXB2W5aFRSH3HzahO+RCND3nH3BZ8whqq/QTJ/yxgLWr4eUtzssyxa/5W5ojylByupkjq1qrJaP2TtxNrzffvt9kcqFexQWRHXRVwDWMeuKqITbWetZsoXLa/CeXPpPGMFCKzJmDrswKBKN6URRV9c4g5ioor1upikfjSJTBXWggrH3N3Yd403NNArRZFkB28pHYsaM5Yrnq3jj5VULCLjIbv89zfOtmY4+fAB6VCNdmg=", + "algid:sign:RSA:digest-PKCS1v15:SHA256": "Y//zjQxsPKxGWeQwIrxrb6dLtAPLQ/u6GhHB/+FLO7XA3Dz37w6k9jbBMHPoKwL0sSZjG2c7tSqWn03chavfDpIz4nxiYBn8zp0C/TYQ0etHMUIrRyteMDuQaOkRCulcYmZ/SDtMGIpB7+qrUqI3LBfHVWA9X45fblk8/JOHNtlwIFOQjCbLhiDgBBbPvJ9uf4Tbq5EIlyf1z6Sr+atNYOUR1Uh/Tf9eS2eTPa13sRgA1I88U2eOYv1EE2sHAKW4sqyogXsWQLielKbKGg9yWt7bfXPt8lXKL6UkCNt8LDb8SUISw/pEW37lpGH7VOMe2NZYiUMKTmqfwuu+7XtKCXVSyolQ+C5qytdOJ7xQOaffeB6tz8u94hE8ltKt1XkuNsS2g1KRJj2Anjd5qAk4hdHMiGpKUCRxEVe0W9D/iSMSYLIlFJSzjPBuDRV2kz80rKO3t00IJAQz18418j/xxClgWcZHHBMDWy9fYWLRYN10RPFhUgwH4r7vp5yjzRLqBy0OD2iXMy40SJkojmmgrTawYa5CGjaIgsP0MbcVrg3RAtla9uh7HLaL/2fP2OSmk8K9x71e8JuWohcRrD5HJMG88t1PBCeHhx1PytZPzx6tI4X3Cs4Q5yTAQLYry53nlf6ZJDc1VE1XJy9ZZEkJ5wwNYK/1OH6TTS0yOA4Yy6Q=", + "algid:sign:RSA:digest-PKCS1v15:SHA384": "rdQyl3D7gaBdXMvTZ4zYzcALr0GL5FWXeDljtEBC8ZgGN0/a3OZMKAnHn5Jp5TX1Flhq1vfRyx+C8vQacOkoXhcbnImGu3A7OJXpuCVO/FC0y2m3TUr+6MnjjkAHZ3sFiNJ+27nd7WV65iTlp7Yka0Yc2Jvqc1+8N15s9m8N0cUkcIRx66NfpNKjHXepK/nqj85r5+8ow3Siolbk7dDIzjPYKo+o27k9uNGGac36Ts+32yGuoCx+zQGzjxE6m9afN/2UQrwNVFk/R0aXHfYf27EESQjCiCdmnCjk2BV1QwCdgrKpbqreYoKL4X9Z7+LaKEXivjxnzov9hfFgeijmlrvCBh5YF59zjWWiEcG8DH+hsxk4Jpn7eas+u4hK+8lIdPtTuNd+Qf9Wc4soJSISNxwKEn9+Gn2KvThxfOW92ZkOs17ffdGGVNndYt0xvh+xhnHWIa4GLVpyE8YLWHgEjk7zXUyGMjrsFziMJeLPvJETi2E4jq2XLyVrydXsVQiCl7pxIKcn69tmkeLwa2kEKCSVwI1opNe+euDoJejU/3ezYcNULrqxeFcsPYx07CDbkioSbJ0/hzAkyLJeZcN+D7LWLbbex866wUFyHXIxuKewWi5gUwGoArelf2Rt/bGTeuEY+5EHae80qLWp55TCTLZpEOXZKyPZ+Q8gWRvWufw=", + "algid:sign:RSA:digest-PKCS1v15:SHA512": "wkUhun+23sf7YnDNnu3FlrFA+GKJpvyrYFrpam0l80AeEvtlc6B6/eBgUKNc/NYnYDtLNMOILromOb6ZVHefpz1nnB8A0Safjf9+URBYeqIILAplRD4WTgFwS8aqENdgF2w51LZwvqIyFXKy6A4Q1EbKkm6/X4VHn6foLz3ELo1lOiEVBv9dcqVlM8onKUtUxRXuY4J3PeNTciUwigdn80hM3bJ1p8GR2dgG89bM5vLXb4MX6vFeXTm1Xyb5oWwaS4XSvbnhbrueTJnBLcCWV3+ILYVgYot99D0gVWI06KH5EPe53SPPBe3Eb3TudqS1sbnmjVeX8avfMfSlbwDNHqADo6z0AFKUQO6/mX6aNb0ei7EcqSSeVRl0IO6vXbB7tVTuJk5/sdW8CGwIybWJGNwxp4b/vTuQvu2BhFzqfnmiqvVln6D6X5latGWAk+6kJPZpayoCXAnsN41dS3Si435h/0LK+/D0uqBaNBG5WUntKqMNibiW9WQpi3NV0T6AuAOp0zBxVih7OYyz5f9D+y0Gvhulg+j9zM0hfx2KKkqEOZfViBLFMZx3nFDCyDpV8ytt08qRjdhozoe5WXy5wUKQ9RZ6fmQWa5zpFZjr5KxwX84Ev9FfAA5l3zt2pLEkIOlH5ubnCCvF7KqJjoR9QhuxJnvVP9pWFg3dhHn+BG8=", + "algid:sign:RSA:message-PKCS1v15:SHA1": "RjcmVMLG3o3FnAH8oYdiFPu+Oy5LsoBEQP2yiHAmSllm3L3bjNt7b8WI8PtZqV4P1XFLqxCWUvbg5+cRo9FHD15+3+5PyQWBdut0LPecrsq/78t9BIXPFWYt2ZPdOhYAV0VxBxd9IGWZ92V8Dtw0xBNoF/nIojWABJne5xOBISeInnSDXATTXp9SUkNSsjyzgHX41W7Y8Ewac84Vfk+ITMvZhl9JZM7+TlL0ydWmf4Rz8EbUy/QZGuqBhfiaddyeRkrhJ6+yiiuLim6oKzUnTWb+UW4Vit3CiExG/OtGYB6Df1HCUZybWhN3N/ovMiTig5iO5z3UAKlWOt6eeB3d9uAspb6dkKmiWvTDqZGM4ldLlI8vm8AkaM3nYx9vLP6fY8KK0CAPeOsJEkx7gcHQSPUac/Pn37LLG4itg1LXG8ceU/hR1VA1YwwMCpGUY4kgoPHXDlqmojBHkNfk99ESgY8WoHe1uWQwo041C8MVFXdRixV5yHMtPpvr2SgRT0HoaxXGxD57EYvP+Kh20O/RvYRsp9aJovWYeuM38SAJB0S07O62WvUweR1KtfmKsNK8Qb2oW1jPjjiZJlAKMp9Ildct0EFqWXucb0RMpUABQeU4vpquYJmUoFnuyi8AB3DD1/As09Ql19Z8f5+QIo3t9X3jkGj8do+dEbwfdpVME/g=", + "algid:sign:RSA:message-PKCS1v15:SHA224": "p3yUPCZDfHDSkalZURc0wUxJajkbf/UdTFJ/bXJznuSQm/wtn88gw9/pDTXdaLrX7yo9JoIX5IloYcpqvPLlflO1jI6HYSTyS9/420qmrL5fzWuFXbmqhHZVQcCtYNntD20JUaLVwm+6ZC7d2FFf7qPJ6K+6Y+Ap6eY5D0YydD9twARI60G7Y5ZTMEc7Q4PkyT08mnFMv3WDc4R0VoU43r3ovk1YT4RGOQwQ22BNs+eSk6ZSaKpWX+vefwoCFjXU5WZ5ycUdmo/x/Qi4+zcNQhK2UifWC35m8ifr/D9/kVaOgLlhgGIjhEEjipNuS9VgCUwjXSJqrHUOygp7woudxAladQdpAwlDJ0a4RBA/0tVjmGPLnNeCXvperAxSYEHUHHlgy9Gr7DDUHYxLuHAbcLyffEggZSi/yPK2dX3eFGNgCeUdQVZPYvr7mviKKxn/klqT3CPPu6wHZJI84IFVHc3NkkH5DSsRdrfKwdGcBRiqW5ZF8rfgHijdj7IR641ZSX01FxBOz5jl2RJZhBYYETS9dtU4b3UGNrNFnwCPE0DbCRBGkoX2wJC9VQDkXDd/n3uXV9quRSNErr6JJSYtZ0oopsMt0ghtRiVzXicp/EmAHeYw5zdc4WI/6ZUQ5MYJrB3HPkMvwbHNpgtu3DNAn9hAJRyzy2DbJbHuNym9QEE=", + "algid:sign:RSA:message-PKCS1v15:SHA256": "v+CUbIaUyg8YrLyrpWzz9mbHWtfcSF2IV8wMEzXj557BQBTzjhVF4kfwbAR2VmhxuuwHOgxi/gxTCBMto2BxPv3VbYPGprBikfXpii5EcoZ/5q7hZes9fw55QPg5z7D0xskQonQ33obcajTfjeaT2p4xRwvBG6BYw8WDifSj/JqGxkXAf1lnuZUTAq6Djw0ZB+kIYdUzBoUSUYrI29nY+uSKH1xLgKbc9UuZt7n/VY9BiygX6WKGoRVsfW74SHHWjBmbaKANcPPVoYAscYVU3toIZOe1nae5ZDxBGliTuoesWwkVSWjaNytfgYRhRE/uo0zQOPK9j5txDQ+mFlo6eheym0v0PF/MvvA+H/XSWHWrZQ4HWmnPIuxsKprLdf4kroSqBb5reM/krsgLsqnDxybOmrlC/WG7fHSYHSfFm9eot1vD2pk7ZnYJHiTFQ2XbdXPMWOIvmGcE1wyGS6zwEEdvyofUopt7NU0hKalsQdfZPAXoOMClEw7ycIhoXy3qVTSyD+PuN63W6jYlHvQDXlbMZWtnneBNtKT/3NMuQk+ff9AZ3YhENUuwFVsT2WfdVF4boNAP3EsP3CjF02K7iGbeG9m+KmOX68+QKHZadm91N67vrjHjh9kx41zOJ5zEirmNW2rBqeqq5wXRIlH1eGTENxgUoo9fi/DYg6zFQaI=", + "algid:sign:RSA:message-PKCS1v15:SHA384": "qCz5z4vf3oeREXrYwx7ii5vGUSzlVxIj/xJbGAnPiS8p1ffOQGbtJXdrzFGiGeje6O+ILqdfOU5mISTUqaH+qh8z14ta7whf3vnis+dEMGv4Re6cBfq5lVu+xHgeScBOaz4WLeY8hs0WsPHCMOkcl6tjs0XujnCODob1yTeRTxnZU582MjDmZheM3Rlc+3aXhgKuYprmgwEcsoqoPlYqd8m3DumXLggL3r9v+nP2gH/8kZNyBrTyjJRf+NQ+Mk/5dkJzNJ87lf6oUR5PGHAdB3ZvLGMQUF42M39ev61sod8Emlbw9vUUdVmdzP86HIs5d3EkWSI0ojR/szmDoKvAI6a9BJvgd/dvNwNrh9KmmQmurGpNbL8fV1Ceoua5wdJ20BPNxmL0H8cnj+iNaSPmcTWlpxEhsieiedIZpRSqDrTqXIJfhUaJSGHLinXrkZ7kR7Et4AVt1Nw+8wujLM2TgLPVLoTNxXXDdOGNqeXCUn0Je9DZJ/VA8FEMT1SNJhkITsTtjMwcc8060NDvGfDrGMnkwK0lIdCR+HDTb+YIzF0vKuYhvE3yOVNT7RHRnQWfM4i06NDoZkuetz8ih2LYBvehh4xjusjo9EGgilogsdvlFMJJSW8iNZ1rNr7/jcbP44iUJVh6Q7xK+X44Fwq1k3cRP63opAFzV4b9Vi8HbZY=", + "algid:sign:RSA:message-PKCS1v15:SHA512": "KBLoU88ueGIlb+eho9Hj7nlO3Lz6gWeqnTArxGs/AOYIIc+/kxC6sEf2r0DrnfGXDWqIBrH6XmjZhPHTbs/N7lamXegBkCeQfk+Qkwu32CX7CZag81D6Qev1ZISM0eKjRT0tNnEBKeebrYukqrUeSe1LR9jbq+y8Y9txpX6/eMgOlm48qsKEm5Z7VOsZCebj+8JTZUYNKqOaxjEvOkVl51MgGj2thaWvPgC9KURywEiML6nIsY29R/9c5gv0bs6Ui7eEdWATcTk+Vahpah5yupTvrqdvZLXE9OUP7eHHN9A0qAOyYT/g5pKef29ydPkA+JSJXeER9oK6OttV5iAJ1bJ4tkVS+WhdZ7DDsUXyj4NOmoPm4DbgzFawFMzlyppKLz/vRTCemiW5S0GYXYf93vd8uTeUAaTq1Ka+i5m5VMRd6kGdpmIHY7OZSZ9Ult1nnBTPCUQFps0vz+i22Y6h9zY1RpAFlca7u/8CyjlSRjaMJNWSNMvrF7bY253mo8oWYIPcYlWx5wsQ7eD2iaS3ac+EimBITJYWEs08vW6GE6venbW2NS1qwwSbXEKeDbLukWXd+B9+MvfayInW538E1C8TlKu5tgpFahWUFefMOdaSbqnePI0Ft52K5MgHWPwzc63e4W/ZxoULl5+MV81S2MUfD+WO9nZ5HM9W2BJUuxs=" + ] + ) +} From 075cd354989331e244083f985ae974829fbd6908 Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Thu, 14 Jul 2022 07:49:07 -0700 Subject: [PATCH 36/52] Deleted signatures file --- Tests/LibP2PCryptoTests/signatures.swift | 188 ----------------------- 1 file changed, 188 deletions(-) delete mode 100644 Tests/LibP2PCryptoTests/signatures.swift diff --git a/Tests/LibP2PCryptoTests/signatures.swift b/Tests/LibP2PCryptoTests/signatures.swift deleted file mode 100644 index c896b97..0000000 --- a/Tests/LibP2PCryptoTests/signatures.swift +++ /dev/null @@ -1,188 +0,0 @@ -// -// signatures.swift -// -// -// Created by Brandon Toms on 6/6/22. -// - -import Foundation - - -struct TestFixtures { - struct Fixture { - let publicPEM:String - let privatePEM:String - let rawMessage:String - let encryptedMessage:[String:String] - let signedMessages:[String:String] - let publicMarshaled:String - let privateMarshaled:String - } - - static let RSA_1024 = Fixture( - publicPEM: """ - -""", - privatePEM: """ ------BEGIN PRIVATE KEY----- -MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANSRvSiXv+gtFt9s -upxbjfG0l2HvFD5V/nsNa2QSl5+Vnl9RMg0P6zUCVMC/rc2x9RfcYn+n7mOGeXfP -B5Mqvt7mFoxmo4loBFIqkbE4HDPUrduG8lb6LNfBSvA9tyaSICW+QCyOPWHBGk0P -y382i4X6E7ActAI++RfxgttTOhmvAgMBAAECgYAyjMnf+l5ft0FGNpQWFMunnBuX -5YP54vdWifVs4eL+x1TXM/bkFlIH1BsVjz+kt9oiJ32g/+1364W9URVrEPI8nk5i -Id40q3Qiozvn4ceWtSoCGmuxIbdRqL1JJn5e8Zfzs7E8KZimYu00t2qcidFDUsEC -biCqT14UNcbpwsOpkQJBAPxMogs3OnkgCWlptZckjg+srwxnXIkzDhSO+WaKl2Dm -DvSMnB2Ws64EDu2dP+HLiuoyqG/ZqRabdQqIsIrkLpkCQQDXr+wYGoOiL26PrAew -z49aH/wQZq8fBM2yuwvR+ZDRraQ0otQV1aRwffqlI+IfYowJvyPX+EC/ftcff0qa -6R+HAkAQZlrSJ9DhNrfl5j0rifDCDBOE1uMo9+yeYXzMsY2NeubV9p3fPoCHezQN -Nf+FCdoJxykzvA5Fre05thDjtllhAkEAgdsf2M81y1KlTQi0xKXiV8+D8dfwvUsm -EOJ+Vlfb8fGKOEqER/UNgNDIM96ryFuLll6m1ONZEDHskMERiLysRwJAawkNDlqe -sIjqrfR2luw+TLHkMI0T6pTY9s+79F9VVV/V13v2qtTpXw1eu7Sw+oDBpJoocz/h -+YzU+CyyzO+qUA== ------END PRIVATE KEY----- -""", - rawMessage: "Hello RSA Signatures!", - encryptedMessage: [ - "algid:encrypt:RSA:raw": "N2T56NKkKAFdCytLP9zT0Iu9N0KNKkflB6vsNl6G+nkY/102laZLSbNZbdkzsOYSIml30ZaQSPS76aBuAYttlnCNEckgwmaS2IpHnFcUUFa/MOf+LJRcDXvkp+NoAmF0QFUhQ+VPfdineUrzOkL+xUi4hY614su6VdfPVmtJeog=", - "algid:encrypt:RSA:PKCS1": "uliKMjgMn54C/WmwagE0dHFrEKw9civz9YYkHS+KKdlqVeCf9qKrFoSHlpA1Mq4JFg0WmpLWaMxgBaD+1CrE4Y+k26+wa4JtffLbyabYrxJkNQ5Am99KnoZO8rLEp2VumxGcsWWseMgSqrlO9KTesD8sJGFCMiz6aSFieedjAu4=" - ], - signedMessages: [ - "algid:sign:RSA:raw" : "zpIDplKEdLvsHopjwoC36mQ3SRg2mZe/0RPP3DaDMnlSDLneoGwzR/L4oR/PTxD34wW7edQV4z5MrFSbmK4a7d+fwvNRQtwYlw/L04GTQyH8G6LhFUKL+++0jdPOMuMXADT8Yfrna6QHti2kqcUE4WSXHe6yY8xZZ6SHEDK71zg=", - "algid:sign:RSA:digest-PKCS1v15" : "s64/o2jeSm9OsTwlBuwJXOkJQPLoT300ZnMPDwfAdKsVFq8vR0uUDgkKYGnaogRu66QTWHfjSPcO2RUKV23141GM6Tng3zv3WGQm2Eg663n+9tYpsV5hCussJAcAwuGHoZwFV79alpNZkFyHEjya189zPeT1K3FbZJniL0ykTuk=", - "algid:sign:RSA:digest-PKCS1v15:SHA1" : "zIqv0mqhlDl0pf/Z5cRuZSP8oskOJhwluNI9EJRBC8b3RXlPlj2BzZyNbN0Mys3joVlfEiw4YsKYKFWN3SwGSwsYfcfeWpDJ5vJF3s32JkXnfHLdspTeapeVYDSy4MS8mNkVbYB6pQFBNK6scfzUFY7pLPKzUJ1MCnRmwpc0MbU=", - "algid:sign:RSA:digest-PKCS1v15:SHA224" : "TS9eVlAFagKSmHtSdjunj3hgqQY5Zu7agjeYPvChB+jPgoqw/H3QwdzA4deZgcmsE1BooCgK9/1iekEWU/tjilVVrkhB5Kq5YxAWA7+IBo5pYFbmsAvP4ka+Oq1urfAYQbzTAuFyEXbdfXQATotElZFHwWjlTvZyk/IFfEawqtg=", - "algid:sign:RSA:digest-PKCS1v15:SHA256" : "bLshLiyA9r2aow0u3+UKTSnyght7+8MuxEFzKsQrKgi9wYNwXsZEToB7jZ6+Y/hbezdIYXHwdtkHmBslAQBEGk+njsggrtWPVSDu/yU6icjEiiEd/35tVzgFejhmhj/5b8odScLrJF+6IeDl4iv9/tQZ7znOGImg5nZSik9c6dI=", - "algid:sign:RSA:digest-PKCS1v15:SHA384" : "N810I+DcCYE7RROmKCHFl7MZl34dHkIx6Y3TxWv5g/JfvZHGRf+TwaFDjD7cGAdV+jY4wZd6mSNZvrhLgfb8t2X5JOaIiDaXt39etAywgE7OuMMYZsD596UBQFrdEu0bQIsK3+D+GcRCNYFVUUsJmYLvo/cio59IcTSRu1f3/5Y=", - "algid:sign:RSA:digest-PKCS1v15:SHA512" : "rvrbc/LRhgGbXq1yAybMxfejAf+GHi4bcrhNKMRtg+RT3iw+Z5KLKzcSWinD9yH1j8NrL8u7EPLNDQ6EGt8y0JYSk0KqwseBpC2/zicu2HTypzFLnrNDtAw6E1A+AVOoAPkxkKf8F/ledih4xKn884USD2jO4ncyoXK4sGj0sjA=", - "algid:sign:RSA:message-PKCS1v15:SHA1" : "BMmnNyAMr8CMYpiZJAngT1o7wDGB1+hrHBHCs5OLcM/bpzqJ8+L9hHnWBeh4hZGcIkRCnB5KFd42WwcNLUQi1EUQHvDDH9gwpT8oPWn7Y/bkflwtKl9A3R1RiobY2rafe5PlbKW+SlN8ddZ0gevt5w7Ob+vQYRLu+e5dSSxVrtY=", - "algid:sign:RSA:message-PKCS1v15:SHA224": "Ro+Y9+TavJt18Bin3+WVVg3YOzPsIlky7LiPXkMdsh1Zq5j3CD23EehNIG2HT3QXSG2ySZuaEj0swJvJWEvcmc1lo8f0xONkgCSk8iKtRzoJ6AJe3abqwc2gNHofzUtJq/eh2ZCO/IFvXC0B4sMIf2ztJuSNRW9O8d0m8zCsHZo=", - "algid:sign:RSA:message-PKCS1v15:SHA256": "kaqP1oUrtRPUTA5uBAcPrIDGQPAqn8uH9pHMFYumS9FwZTYlRAeCFliMuiyW79x+x+BOC6TX+mipXgWJIO1IaucyrLBKlak934SX6q71xWA74SSYlMEzalKPFpi879fvgGyY4fRypJQv5uZ3nvlvxAhyB/pX7jaV07ct9sKIQv4=", - "algid:sign:RSA:message-PKCS1v15:SHA384": "hxsA7RjGU97s1erJAv1WTkscZk61NHv55s0BWHoJEXgda0WulbcnOQduZJWeSyxJjRh4kGztV42xOvMpo9qcovbYOI3hQJ210gbNTBKmTp9tG79ShV6lx07eceC2XZg9kYxtgkuSpurRjd2PFbkGFGhTZmqRaSQukPjSIhnxoyQ=", - "algid:sign:RSA:message-PKCS1v15:SHA512": "r31GD74cN5wknycZDyNZdJ4HJBBLv5zMH+dmfYW98i3szDS8txdr0M8ZrmM0jLxcSpwa5461vwMBhyCOYlqY2y3HoKNolIDSANhWPufKFMcv+ob3okNDQGXOAyPKhxn/EW7X2Mz3XQlBnOA6c18KR3UnZvoW5wn9K1tpv4ueEyI=" - ], - publicMarshaled: "CAASogEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANSRvSiXv+gtFt9supxbjfG0l2HvFD5V/nsNa2QSl5+Vnl9RMg0P6zUCVMC/rc2x9RfcYn+n7mOGeXfPB5Mqvt7mFoxmo4loBFIqkbE4HDPUrduG8lb6LNfBSvA9tyaSICW+QCyOPWHBGk0Py382i4X6E7ActAI++RfxgttTOhmvAgMBAAE=", - privateMarshaled: "CAAS4AQwggJcAgEAAoGBANSRvSiXv+gtFt9supxbjfG0l2HvFD5V/nsNa2QSl5+Vnl9RMg0P6zUCVMC/rc2x9RfcYn+n7mOGeXfPB5Mqvt7mFoxmo4loBFIqkbE4HDPUrduG8lb6LNfBSvA9tyaSICW+QCyOPWHBGk0Py382i4X6E7ActAI++RfxgttTOhmvAgMBAAECgYAyjMnf+l5ft0FGNpQWFMunnBuX5YP54vdWifVs4eL+x1TXM/bkFlIH1BsVjz+kt9oiJ32g/+1364W9URVrEPI8nk5iId40q3Qiozvn4ceWtSoCGmuxIbdRqL1JJn5e8Zfzs7E8KZimYu00t2qcidFDUsECbiCqT14UNcbpwsOpkQJBAPxMogs3OnkgCWlptZckjg+srwxnXIkzDhSO+WaKl2DmDvSMnB2Ws64EDu2dP+HLiuoyqG/ZqRabdQqIsIrkLpkCQQDXr+wYGoOiL26PrAewz49aH/wQZq8fBM2yuwvR+ZDRraQ0otQV1aRwffqlI+IfYowJvyPX+EC/ftcff0qa6R+HAkAQZlrSJ9DhNrfl5j0rifDCDBOE1uMo9+yeYXzMsY2NeubV9p3fPoCHezQNNf+FCdoJxykzvA5Fre05thDjtllhAkEAgdsf2M81y1KlTQi0xKXiV8+D8dfwvUsmEOJ+Vlfb8fGKOEqER/UNgNDIM96ryFuLll6m1ONZEDHskMERiLysRwJAawkNDlqesIjqrfR2luw+TLHkMI0T6pTY9s+79F9VVV/V13v2qtTpXw1eu7Sw+oDBpJoocz/h+YzU+CyyzO+qUA==" - ) -} - - -//func testRSAPEMImportSignAndVerify() throws { -// let expectedSignature: Array = [ -// 0x76, 0xEB, 0x7F, 0x10, 0x95, 0x40, 0xC9, 0x19, 0xE6, 0x44, 0x6F, 0xCD, 0x88, 0x83, 0x22, 0x6E, -// 0x5C, 0xE4, 0x1E, 0x87, 0xE3, 0xAF, 0x3B, 0x59, 0xB7, 0xB2, 0x89, 0xFD, 0x88, 0x37, 0xC0, 0xCE, -// 0xEA, 0x0E, 0x87, 0x06, 0x5F, 0x6E, 0xE7, 0x8C, 0xE9, 0x3F, 0xD6, 0xC3, 0xE0, 0x0B, 0x94, 0x19, -// 0xAC, 0x58, 0x2D, 0x73, 0xD3, 0x92, 0x45, 0x2C, 0x66, 0x7F, 0xB5, 0x24, 0xC6, 0xEA, 0xC6, 0xE2, -// 0x0E, 0xBB, 0x12, 0x86, 0x5B, 0xF4, 0x1D, 0x25, 0x2F, 0x68, 0x69, 0x30, 0x80, 0x4D, 0x10, 0xDF, -// 0x25, 0x5E, 0x00, 0x1D, 0x2F, 0x5F, 0x67, 0xE5, 0x4C, 0x7D, 0x1E, 0x64, 0xB2, 0x0B, 0xE8, 0x19, -// 0xE6, 0xB8, 0x62, 0xA6, 0xD1, 0x66, 0x58, 0x47, 0xAC, 0xAB, 0xAB, 0xCD, 0x26, 0x3D, 0x16, 0x52, -// 0xBF, 0x35, 0xB0, 0x21, 0xE2, 0xE3, 0x48, 0x77, 0x1E, 0x81, 0xE8, 0xCF, 0x75, 0x67, 0x64, 0x2A -// ] -// -// let message = "Hello RSA Signatures!".data(using: .utf8)! -// -// let keyPair = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.RSA_1024_PRIVATE) -// -// let secKey = try initSecKey(rawRepresentation: keyPair.privateKey!.rawRepresentation) -// -// let privateMarshaled = try keyPair.privateKey?.marshal() -// print(privateMarshaled!.asString(base: .base64Pad)) -// -// let publicMarsheled = try keyPair.marshalPublicKey() -// print(publicMarsheled.asString(base: .base64Pad)) -// -// let pemData = try secKey.extractPubKey().rawRepresentation() -// -// let pem = "-----BEGIN PUBLIC KEY-----\n" + pemData.asString(base: .base64Pad).split(intoChunksOfLength: 64).joined(separator: "\n") + "\n-----END PUBLIC KEY-----" -// -// print(pem) -// -// try sign(message: message, using: secKey)//keyPair.sign(message: message) -// -// try encrypt(data: message, with: secKey.extractPubKey()) -// -//// printHexData16BytesWide(signature.bytes) -//// print(signature.asString(base: .base64Pad)) -//// -//// XCTAssertEqual(signature.bytes, expectedSignature) -//} - -//private func printHexData16BytesWide(_ bytes:[UInt8]) { -// print(bytes.toHexString().split(intoChunksOfLength: 32).map { $0.split(intoChunksOfLength: 2).map { "0x\($0.uppercased())" }.joined(separator: ", ") }.joined(separator: ",\n")) -//} -// -//private func initSecKey(rawRepresentation raw: Data) throws -> SecKey { -// let attributes: [String:Any] = [ -// kSecAttrKeyType as String: kSecAttrKeyTypeRSA, -// kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, -// kSecAttrKeySizeInBits as String: 1024, -// kSecAttrIsPermanent as String: false -// ] -// -// var error:Unmanaged? = nil -// guard let secKey = SecKeyCreateWithData(raw as CFData, attributes as CFDictionary, &error) else { -// throw NSError(domain: "Error constructing SecKey from raw key data: \(error.debugDescription)", code: 0, userInfo: nil) -// } -// -// return secKey -//} - -//private func sign(message: Data, using key: SecKey) throws { -// let algorithms:[SecKeyAlgorithm] = [ -// .rsaSignatureRaw, -// //.rsaSignatureDigestPSSSHA1, -// //.rsaSignatureDigestPSSSHA224, -// //.rsaSignatureDigestPSSSHA256, -// //.rsaSignatureDigestPSSSHA384, -// //.rsaSignatureDigestPSSSHA512, -// .rsaSignatureDigestPKCS1v15Raw, -// .rsaSignatureDigestPKCS1v15SHA1, -// .rsaSignatureDigestPKCS1v15SHA224, -// .rsaSignatureDigestPKCS1v15SHA256, -// .rsaSignatureDigestPKCS1v15SHA384, -// .rsaSignatureDigestPKCS1v15SHA512, -// //.rsaSignatureMessagePSSSHA1, -// //.rsaSignatureMessagePSSSHA224, -// //.rsaSignatureMessagePSSSHA256, -// //.rsaSignatureMessagePSSSHA384, -// //.rsaSignatureMessagePSSSHA512, -// .rsaSignatureMessagePKCS1v15SHA1, -// .rsaSignatureMessagePKCS1v15SHA224, -// .rsaSignatureMessagePKCS1v15SHA256, -// .rsaSignatureMessagePKCS1v15SHA384, -// .rsaSignatureMessagePKCS1v15SHA512, -// ] -// -// for algo in algorithms { -// var error: Unmanaged? -// -// // Sign the data -// guard let signature = SecKeyCreateSignature( -// key, -// algo, -// message as CFData, -// &error) as Data? -// else { print("\"\(algo.rawValue)\": \"nil\","); continue } -// -// // Throw the error if we encountered one -// if let error = error { print("\"\(algo.rawValue)\": \"\(error.takeRetainedValue())\","); continue } -// -// // Return the signature -// print("\"\(algo.rawValue)\": \"\(signature.asString(base: .base64Pad))\",") -// } -// -//} - -//private func encrypt(data: Data, with key:SecKey) throws { -// let algorithms:[SecKeyAlgorithm] = [ -// .rsaEncryptionRaw, -// .rsaEncryptionPKCS1 -// ] -// -// for algo in algorithms { -// var error:Unmanaged? -// guard let encryptedData = SecKeyCreateEncryptedData(key, .rsaEncryptionPKCS1, data as CFData, &error) else { -// print("\"\(algo.rawValue)\": \"\(error?.takeRetainedValue().localizedDescription ?? "nil")\","); continue -// } -// print("\"\(algo.rawValue)\": \"\((encryptedData as Data).asString(base: .base64Pad))\",") -// } -//} From bebeae74becbd5962c1c21c64b9f78858c48c41f Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Thu, 14 Jul 2022 07:49:46 -0700 Subject: [PATCH 37/52] Added comments to our ASN1 enumerations --- Sources/LibP2PCrypto/PEM/ASN1/ASN1.swift | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Sources/LibP2PCrypto/PEM/ASN1/ASN1.swift b/Sources/LibP2PCrypto/PEM/ASN1/ASN1.swift index 388a898..1455ae1 100644 --- a/Sources/LibP2PCrypto/PEM/ASN1/ASN1.swift +++ b/Sources/LibP2PCrypto/PEM/ASN1/ASN1.swift @@ -36,13 +36,24 @@ enum ASN1 { /// An ASN1 node enum Node:CustomStringConvertible { + /// An array of more `ASN1.Node`s case sequence(nodes: [Node]) + /// An integer case integer(data: Data) + /// An objectIdentifier case objectIdentifier(data: Data) + /// A null object case null + /// A bitString case bitString(data: Data) + /// An octetString case octetString(data: Data) + + //Exteneded Params + + /// Elliptic Curve specific objectIdentifier case ecObject(data: Data) + /// Elliptic Curve specific bitString case ecBits(data: Data) var description: String { From e8c797b25cc1790ce4929a50c74b3607a083b40b Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sat, 17 Sep 2022 09:06:45 -0700 Subject: [PATCH 38/52] Moved files --- Tests/LibP2PCryptoTests/marshaled.swift | 46 -- Tests/LibP2PCryptoTests/pem.swift | 586 ------------------------ 2 files changed, 632 deletions(-) delete mode 100644 Tests/LibP2PCryptoTests/marshaled.swift delete mode 100644 Tests/LibP2PCryptoTests/pem.swift diff --git a/Tests/LibP2PCryptoTests/marshaled.swift b/Tests/LibP2PCryptoTests/marshaled.swift deleted file mode 100644 index c9c6cd6..0000000 --- a/Tests/LibP2PCryptoTests/marshaled.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// marshaled.swift -// -// Created by Brandon Toms on 5/1/22. -// - -import Foundation - -/// Base64 Padded -struct MarshaledData { - /// A marshaled (base64padded) private 1024bit RSA key - /// - /// - Note: Generated via SecKey in swift-libp2p v0.1.0 - static let PRIVATE_RSA_KEY_1024 = "CAAS4AQwggJcAgEAAoGBAN2RGr5akx6ZTvpr3lZfSBU2YAo8s9Zu9B3XQcSjQPZyFTr3c3+XAJDIkpwSaXuc2EUdGP2yxzkShAt1hnibwESVV6lXtomB9mfIdvlh7J4Y1kP9wwF1KedTP4MNlVvaHZ7K+/5lyp+GObNAJJU/YnY/kz6kwUI7r0J948xDJdnlAgMBAAECgYB34EQ57UNf8M58StRWouKbJ3o6z7D1Ob62Tnp062cAb6Tw7GT/CTHzI7G+429Sw/93FVEqIgoL5OqwUHva0VnqP4dunGHHsG+KGwVqL0/6Sr/qkg9Mc3B7StI7QvFgnKQtzMlbFN6ijF0rGXaAh4gcnxzcJyT/KnxePbIyNOtfgQJBAPcbEmXbwIcPyT6QOwR8wwtDh+5GFSndJontFcd7ntC+6mqDuFaCpAd7yBeQcBOvHWOp/FbCBzJCEXFLWFcKgLECQQDlirT7AaujIMODtdBAG+Cxk62XmMX7AkD40Twn/URHJr91oUTJkZmLP6XjGR6kzRAeKfQr/3HpPnWx1uBBM9l1AkEAxD7rzZlIvfr7iIRjWpz7CecH/WQLSsQn50IzGcpDxuTYpt8Vdx8pxge4UX6UhA1++bf2f7B4pqFx2NhNwFLHAQJAMxgZCPZqOjmEy8CgxmRuM5jnvyLmjuUFiV0pws0BccUSQSDQqv2Z7AES7+YbiBuNRumXzGNj+8NHd3qZGGpuMQJAIgoySo2stOX3gTnlF5sPXFuiUjth3vhuzms15yeSqOs22Xew05TqVhoqYuWWjk1E2+Af5YAHKIbOEiVqSnzZEQ==" - /// A marshaled (base64padded) public 1024bit RSA key - /// - /// - Note: Generated via SecKey in swift-libp2p v0.1.0 - static let PUBLIC_RSA_KEY_1024 = "CAASogEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAN2RGr5akx6ZTvpr3lZfSBU2YAo8s9Zu9B3XQcSjQPZyFTr3c3+XAJDIkpwSaXuc2EUdGP2yxzkShAt1hnibwESVV6lXtomB9mfIdvlh7J4Y1kP9wwF1KedTP4MNlVvaHZ7K+/5lyp+GObNAJJU/YnY/kz6kwUI7r0J948xDJdnlAgMBAAE=" - - /// A marshaled (base64padded) private 2048bit RSA key - /// - /// - Note: I think this came from a GO or JS test fixture - static let PRIVATE_RSA_KEY_2048 = "CAASpgkwggSiAgEAAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAECggEAZtju/bcKvKFPz0mkHiaJcpycy9STKphorpCT83srBVQi59CdFU6Mj+aL/xt0kCPMVigJw8P3/YCEJ9J+rS8BsoWE+xWUEsJvtXoT7vzPHaAtM3ci1HZd302Mz1+GgS8Epdx+7F5p80XAFLDUnELzOzKftvWGZmWfSeDnslwVONkL/1VAzwKy7Ce6hk4SxRE7l2NE2OklSHOzCGU1f78ZzVYKSnS5Ag9YrGjOAmTOXDbKNKN/qIorAQ1bovzGoCwx3iGIatQKFOxyVCyO1PsJYT7JO+kZbhBWRRE+L7l+ppPER9bdLFxs1t5CrKc078h+wuUr05S1P1JjXk68pk3+kQKBgQDeK8AR11373Mzib6uzpjGzgNRMzdYNuExWjxyxAzz53NAR7zrPHvXvfIqjDScLJ4NcRO2TddhXAfZoOPVH5k4PJHKLBPKuXZpWlookCAyENY7+Pd55S8r+a+MusrMagYNljb5WbVTgN8cgdpim9lbbIFlpN6SZaVjLQL3J8TWH6wKBgQDSChzItkqWX11CNstJ9zJyUE20I7LrpyBJNgG1gtvz3ZMUQCn3PxxHtQzN9n1P0mSSYs+jBKPuoSyYLt1wwe10/lpgL4rkKWU3/m1Myt0tveJ9WcqHh6tzcAbb/fXpUFT/o4SWDimWkPkuCb+8j//2yiXk0a/T2f36zKMuZvujqQKBgC6B7BAQDG2H2B/ijofp12ejJU36nL98gAZyqOfpLJ+FeMz4TlBDQ+phIMhnHXA5UkdDapQ+zA3SrFk+6yGk9Vw4Hf46B+82SvOrSbmnMa+PYqKYIvUzR4gg34rL/7AhwnbEyD5hXq4dHwMNsIDq+l2elPjwm/U9V0gdAl2+r50HAoGALtsKqMvhv8HucAMBPrLikhXP/8um8mMKFMrzfqZ+otxfHzlhI0L08Bo3jQrb0Z7ByNY6M8epOmbCKADsbWcVre/AAY0ZkuSZK/CaOXNX/AhMKmKJh8qAOPRY02LIJRBCpfS4czEdnfUhYV/TYiFNnKRj57PPYZdTzUsxa/yVTmECgYBr7slQEjb5Onn5mZnGDh+72BxLNdgwBkhO0OCdpdISqk0F0Pxby22DFOKXZEpiyI9XYP1C8wPiJsShGm2yEwBPWXnrrZNWczaVuCbXHrZkWQogBDG3HGXNdU4MAWCyiYlyinIBpPpoAJZSzpGLmWbMWh28+RJS6AQX6KHrK1o2uw==" - /// A marshaled (base64padded) public 2048bit RSA key - /// - /// - Note: I think this came from a GO or JS test fixture - static let PUBLIC_RSA_KEY_2048 = "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAE=" - - /// A marshaled (base64padded) private 3072bit RSA key - /// - /// - Note: Generated via SecKey in swift-libp2p v0.1.0 - static let PRIVATE_RSA_KEY_3072 = "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" - /// A marshaled (base64padded) public 3072bit RSA key - /// - /// - Note: Generated via SecKey in swift-libp2p v0.1.0 - static let PUBLIC_RSA_KEY_3072 = "CAASpgMwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDZSv/m42dihS3dBZ6+265BQWgvCf5oPRwQieekWSpy14Zk+FaWAORry9/1X7HZYqTCrFNo9JUt9Qo9HDv//aGcIs6zhuSYNCy85hCBAUd/S9TTzx5qeimUZ1/Gm0VMPtpxUhZqt2V23/BcBFsUO40f0uibOA3BkftIMlNCJptlZ/cAlULFKs5bua6tEiWycuOrcbigvzrkbc/vDaRCOBPsLGOY/ljSpc74r75sEC9brbBPxMknpJ8o4YG/V1jo+t15WbILqPPEKm1m8RRuTZSeSOw1S/GlcD1c6HCeX9ms6kmA0LcOv/eSmHqiLCtXybOJFPxTvfbBlQyAwUf4gUj8HDrgfq9i6ldlEP6RfduBZPMvX7yEVDmoz1KtSX+usXC73gfwlZU9Rrwg8jkR9bl1G8c5J8nKiWIdxgq9HGY/CVVl9IsXf0m+0NNLEAClBIUbp9+7QH72wrnzcI6eAqAxMyUGcuqxcXQC4RMuCPE19eeUA4L+hbmyXzXAG+jMWDsCAwEAAQ==" - - /// A marshaled (base64padded) private 4096bit RSA key - /// - /// - Note: Generated via SecKey in swift-libp2p v0.1.0 - static let PRIVATE_RSA_KEY_4096 = "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" - /// A marshaled (base64padded) public 4096bit RSA key - /// - /// - Note: Generated via SecKey in swift-libp2p v0.1.0 - static let PUBLIC_RSA_KEY_4096 = "CAASpgQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQD3FcFG9iBVJA51KOMXlgDEeizTKBmJ25BpvX+RfhhDyl7NtEKO3WzidPuvpUngc39TmXbyN8ZlOCiMR7AOeRlBrcGgeeFXAljXUnwcGAnG8u19WeF8x64Xzl5I48i/hN/zxQ/YHGyyyvMOowh0s/XEmsbzZb8fmeRhkIeGt1DY16tAnewmV83Vn596yZHtA6RIAQMtcdCwVB0+DfZ+WPya3FHuTdVztmUzfKCatCUNr9NI4TXHgf+7BRu2idVbQ3khh/axAo+0c2htHs6b+AQ1rxZoEoB2f4YUL6ICj8zkJVC4pE1hraRMLR4ExPUb0mvy/DJq5T7+OcxO/Y/dskpsdyo0j00simHPeEmUuP45A7AbYTr7MKInMqlKBOLM+yORn8CDlKiT6cDkLD2oowUtf0wI8LK0D+fAg/5GwJtSg2uHRUWQFv19KkOUHuR8T/HYyGelBsKPZZ5O46BLD7PSYdTFHvNiURxOQKmZYeGhuBJ2wp0q6R+Evvdvwcu+PcGCQIuQb9mAdtHeS2oZjCxY+czsYy2pUHxxuGSpBI+aQLwRMFhpm0B/WMcjLOLFH88qNa7U8ksxZpLZufnBxuiqfX+FGKga3Jj7dv1oV+oFxTvndHhZL0JQDTylnuv79T1KYOVzxNWAJsaPXKUUbOhm4kdDHUY2RhEJMh2QVDitcwIDAQAB" -} diff --git a/Tests/LibP2PCryptoTests/pem.swift b/Tests/LibP2PCryptoTests/pem.swift deleted file mode 100644 index dc136fc..0000000 --- a/Tests/LibP2PCryptoTests/pem.swift +++ /dev/null @@ -1,586 +0,0 @@ -// -// pem.swift -// -// -// Created by Brandon Toms on 5/1/22. -// - -import Foundation - - -struct TestPEMKeys { - - // MARK: RSA Keys - - /// DER Format - static let RSA_1024_PUBLIC_DER = """ - -----BEGIN RSA PUBLIC KEY----- - MIGJAoGBANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXY - UMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE - 3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dV - ek9b9VAgMBAAE= - -----END RSA PUBLIC KEY----- - """ - - /// RSA 1024 Public Key - /// - /// openssl asn1parse -i -in rsa_1024_pub.pem - /// ``` - /// 0:d=0 hl=3 l= 159 cons: SEQUENCE - /// 3:d=1 hl=2 l= 13 cons: SEQUENCE - /// 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption - /// 16:d=2 hl=2 l= 0 prim: NULL - /// 18:d=1 hl=3 l= 141 prim: BIT STRING - /// ``` - static let RSA_1024_PUBLIC = """ - -----BEGIN PUBLIC KEY----- - MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUkb0ol7/oLRbfbLqcW43xtJdh - 7xQ+Vf57DWtkEpeflZ5fUTIND+s1AlTAv63NsfUX3GJ/p+5jhnl3zweTKr7e5haM - ZqOJaARSKpGxOBwz1K3bhvJW+izXwUrwPbcmkiAlvkAsjj1hwRpND8t/NouF+hOw - HLQCPvkX8YLbUzoZrwIDAQAB - -----END PUBLIC KEY----- - """ - - /// RSA 2048 Public Key - /// - /// openssl asn1parse -i -in rsa_2048_pub.pem - /// ``` - /// 0:d=0 hl=4 l= 290 cons: SEQUENCE - /// 4:d=1 hl=2 l= 13 cons: SEQUENCE - /// 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption - /// 17:d=2 hl=2 l= 0 prim: NULL - /// 19:d=1 hl=4 l= 271 prim: BIT STRING - /// ``` - static let RSA_2048_PUBLIC = """ - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxoLE8VNgeYQxGt5x++zW - 5INUrgTGhcrgEjDt8J78xAQ9UVZdya4q1PP79UPKb3xVvFHHAKQ2tEzzgpZvv2h8 - M/DCzvltWpsZwVx5lMiDA71xucRdF5Uiy5IiVdObIEswIN/x9AE21VJEqPihzPZf - AGKdpd8NkeaHnAnq4Pm5uJt9S+82U5iDQzufqm5S0YTTnmpmn6guCN7H2q9WENIi - D3mKxYzmDNyzxEhpS9jMKubvGM8p4dRSFFzQlWO1mIuO0Lf2QkgZsFMNNAEZg3ww - LP1OO288oXz8iAapfoLq3W+I2Jg4bOarHxSIvO2zSCZ1eagUCiHAtYfbWHAugoc5 - cQIDAQAB - -----END PUBLIC KEY----- - """ - - /// RSA 3072 Public Key - /// - /// openssl asn1parse -i -in rsa_3072_pub.pem - /// ``` - /// 0:d=0 hl=4 l= 418 cons: SEQUENCE - /// 4:d=1 hl=2 l= 13 cons: SEQUENCE - /// 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption - /// 17:d=2 hl=2 l= 0 prim: NULL - /// 19:d=1 hl=4 l= 399 prim: BIT STRING - /// ``` - static let RSA_3072_PUBLIC = """ - -----BEGIN PUBLIC KEY----- - MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0F50xB4o1O2y9Avm+YW2 - v9t5HHDI7kuWL/VxQE1R6FkpgLYQ0tUlB2QWGigYUhRS1f2ql1s7LXUVceUesHzH - oXlzmt3Rnow9doASPROlyAcNrzniMyDzH6hz2xaVsaj3Kygc9evQzuf1Rq1R0/bj - AkIlssumizfv70FZrmKBcgp5X9seC/wo3kWIRBV/Akx5vom0V6TEupy/39TDffnK - a3rN9yb7+ZGrHMoXofkd+pYATyIbuwsjeCU0F2v6+pbkXDrB0bgsp6/FRx8Tw9CF - gKf1JESSjeRQIk8nKXiqiNPmmOXvKH39lyEhWetcpn1E+bv7a4TAu1wy/FzLNp9w - NxB5zLX6gqxUDM0YUpsPMftB2dlixO0yzLcvbUohceIb03L4mBsvWfQ3W7yYkzBo - XTsPWofPw/jQY2IorGTKH4vgbQfW3fmqj1CXqgLEOe6XbWkcXyUnTp3Z24RiL5Ql - dqZJs8yEKZqNP9/miIS83Onc1zjWovT7LLFCnucNgoOHAgMBAAE= - -----END PUBLIC KEY----- - """ - - /// RSA 4096 Public Key - /// - /// openssl asn1parse -i -in rsa_4096_pub.pem - /// ``` - /// 0:d=0 hl=4 l= 546 cons: SEQUENCE - /// 4:d=1 hl=2 l= 13 cons: SEQUENCE - /// 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption - /// 17:d=2 hl=2 l= 0 prim: NULL - /// 19:d=1 hl=4 l= 527 prim: BIT STRING - /// ``` - static let RSA_4096_PUBLIC = """ - -----BEGIN PUBLIC KEY----- - MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA96lgFtImy0lK6uxopyli - o5WwN5FIxNdQXE6NL5o6t5Lwd3r/FCq+C1ix1Pb73lU0nJv64rCkgNn5U9rYv4e8 - /Eyu2Egp+2Ff1mBpPnNUU2oqe3de/cf8EyFR8+bQqS+cl5VSCOK2Bp87WlnjBBd7 - vy8UfjrDTIj63tNQADq/OkoUye9q7PPunTIVTvbRlC1vwVDPiCLIPUniRqAv44cG - qM1zxRMhJTEVWJhjnaMy/NJmJQPJvnsiED3aEi/uxsUaxhpKa6JfFL8doPbeydeb - 2NE+ynG6lCYjoqmSZU+9KSwaDtutV8U8LEP9B5cHS8thdyH7uFKjGt3kgD8bVtbT - UGL/zWWcPaqJktlM8iOh+arugW5C/fwZa1GkZZc2+Btq2MfEJ/8cSzp4nyQCk3ye - kCQPW+7wetbqadXMpvWHFQA3HHyPEdPFF4lImSH38c0WzTWaBpXeN5dcP1T5iY+Y - iQ7ZUSMrz8ImeYjAexHkVtE3uwaW77oBGJ33rwEXC0Agdo03mtQdKcEfB4l7gJ1G - Tg8KWPPK0bEHew+OZxiZRfrVnGRhPVGQ5w9Kuib6Q5tP8udsEgZIZUHftf7qdscU - kFc67jbydCj+HCD1Nvmja5u+GdJyQa021y2xbLINPaSTT1Ro8ttWRUM12Y4QEbuI - IwumfplSdLsojGNWVCpfxAsCAwEAAQ== - -----END PUBLIC KEY----- - """ - - /// RSA 1024 Private Key - /// - /// openssl asn1parse -i -in rsa_1024_priv.pem - /// ``` - /// 0:d=0 hl=4 l= 630 cons: SEQUENCE - /// 4:d=1 hl=2 l= 1 prim: INTEGER :00 - /// 7:d=1 hl=2 l= 13 cons: SEQUENCE - /// 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption - /// 20:d=2 hl=2 l= 0 prim: NULL - /// 22:d=1 hl=4 l= 608 prim: OCTET STRING [HEX DUMP]:3082...AA50 - /// ``` - static let RSA_1024_PRIVATE = """ - -----BEGIN PRIVATE KEY----- - MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANSRvSiXv+gtFt9s - upxbjfG0l2HvFD5V/nsNa2QSl5+Vnl9RMg0P6zUCVMC/rc2x9RfcYn+n7mOGeXfP - B5Mqvt7mFoxmo4loBFIqkbE4HDPUrduG8lb6LNfBSvA9tyaSICW+QCyOPWHBGk0P - y382i4X6E7ActAI++RfxgttTOhmvAgMBAAECgYAyjMnf+l5ft0FGNpQWFMunnBuX - 5YP54vdWifVs4eL+x1TXM/bkFlIH1BsVjz+kt9oiJ32g/+1364W9URVrEPI8nk5i - Id40q3Qiozvn4ceWtSoCGmuxIbdRqL1JJn5e8Zfzs7E8KZimYu00t2qcidFDUsEC - biCqT14UNcbpwsOpkQJBAPxMogs3OnkgCWlptZckjg+srwxnXIkzDhSO+WaKl2Dm - DvSMnB2Ws64EDu2dP+HLiuoyqG/ZqRabdQqIsIrkLpkCQQDXr+wYGoOiL26PrAew - z49aH/wQZq8fBM2yuwvR+ZDRraQ0otQV1aRwffqlI+IfYowJvyPX+EC/ftcff0qa - 6R+HAkAQZlrSJ9DhNrfl5j0rifDCDBOE1uMo9+yeYXzMsY2NeubV9p3fPoCHezQN - Nf+FCdoJxykzvA5Fre05thDjtllhAkEAgdsf2M81y1KlTQi0xKXiV8+D8dfwvUsm - EOJ+Vlfb8fGKOEqER/UNgNDIM96ryFuLll6m1ONZEDHskMERiLysRwJAawkNDlqe - sIjqrfR2luw+TLHkMI0T6pTY9s+79F9VVV/V13v2qtTpXw1eu7Sw+oDBpJoocz/h - +YzU+CyyzO+qUA== - -----END PRIVATE KEY----- - """ - - /// RSA 2048 Private Key - /// - /// openssl asn1parse -i -in rsa_2048_priv.pem - /// ``` - /// 0:d=0 hl=4 l=1214 cons: SEQUENCE - /// 4:d=1 hl=2 l= 1 prim: INTEGER :00 - /// 7:d=1 hl=2 l= 13 cons: SEQUENCE - /// 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption - /// 20:d=2 hl=2 l= 0 prim: NULL - /// 22:d=1 hl=4 l=1192 prim: OCTET STRING [HEX DUMP]:3082...59D7 - /// ``` - static let RSA_2048_PRIVATE = """ - -----BEGIN PRIVATE KEY----- - MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDGgsTxU2B5hDEa - 3nH77Nbkg1SuBMaFyuASMO3wnvzEBD1RVl3JrirU8/v1Q8pvfFW8UccApDa0TPOC - lm+/aHwz8MLO+W1amxnBXHmUyIMDvXG5xF0XlSLLkiJV05sgSzAg3/H0ATbVUkSo - +KHM9l8AYp2l3w2R5oecCerg+bm4m31L7zZTmINDO5+qblLRhNOeamafqC4I3sfa - r1YQ0iIPeYrFjOYM3LPESGlL2Mwq5u8Yzynh1FIUXNCVY7WYi47Qt/ZCSBmwUw00 - ARmDfDAs/U47bzyhfPyIBql+gurdb4jYmDhs5qsfFIi87bNIJnV5qBQKIcC1h9tY - cC6ChzlxAgMBAAECggEBAJvNVR+HbgfRvey1vEaa+4p8nUC7lMi7kyQT7RxW3FJI - dYvaOmApZ4qeOBmm7EKWFoBousUBHcJjRxguVGSpcBogE/X4hGCBrTQ7DV2+Bj4w - OQsxWFNDBP07o+Ey5OTyvkJ/Idp9/XhuSl9ITU2d7LBTtiHSsEbb5YGNsyCCP8bo - OP/PQZPDgXz9vLg674rPgm32cHPIWDomspJ34EkD/szyQOpW2AM99v3NbqovM8ie - T91266iPASTngGQG3qA54zJ91Ulu7kx+LNYpSknZOvWxrxDB8+oArdEZFuPpT5L6 - OKj5ICJCFRkiROE2xErn/nUmu4R1AA3WDnFZQMzGFAECgYEA5dDYyHUhtjlM13OL - hUoiBWk4yzz3wB/jcvvdq8OVU0nWeuTiZh4cPSDp67q4AAffAbJvsqYomyA/Eqt/ - NNZKE7ZP9a+KFXbyd1BtDgFiVEcNGNZ0K7beQEbVlG7sFN+s8YT7eeObBoXyhhPA - WC6fWcYfrZatCuNAmcjutoWCarECgYEA3SDViFs2Eb5II9DHwljNJF8gFgRJhAKj - bMEGUVgSK8WWQIO2ZdzlA1kV+U0S5FXx3zyQAWVqCkdAzFB4sZjmT47NZN4cvo30 - E32rXWDoNbKpljBvEhx2HUMA+Zpdpe/vZUHlNpqGT0MZaP6nPTg79EsBdiMvVC8l - 3UC7XW5f6sECgYA1AMzutq0WxPJnAnwcOrPMAa+amC4fvnsLyvEeK1amRfJUl7Nr - j+g9ZPjuaDsFrssNLiU6072rwW0qlikZe47MKxEX/etf9fYH9KGiSElwXI61ushC - SMPLmUqrGEYUrl3JujzxqL/Zak08BRQogmA4KUynEYhJaY49qaz8paAlkQKBgDer - U3avl84hvGGf5xprZsHYXOiODb/5NhFkCuYhqPlyFeCKCDpewRz1qY2ItM/dPzY3 - Nf3T/T03MP3+6FO1rY2r4tOZA12JuT/K7IBmrC8Qmpcf/GZv2eCGBNHR5e+nlvpD - +6OihVuhBd2j9pB3/sgCtgx60Sh9cifgawsbhXRBAoGBALXBsU6d6TRU0PTOwvos - zV4dWva41cuElT1hp4rzgSgRtUIbaFVpGi4STb/B3znvlE4VNsePgq2oe6c4Bx7l - JwZ4bU1ZvxWZ+tLdYnelwhfgq/14tjWPGvlE+bF7s1irJIHsTsoShF+RfavhqVXF - 6FyFEjB0XDmXjJgIxkenwlnX - -----END PRIVATE KEY----- - """ - - /// RSA 3072 Private Key - /// - /// openssl asn1parse -i -in rsa_3072_priv.pem - /// ``` - /// 0:d=0 hl=4 l=1791 cons: SEQUENCE - /// 4:d=1 hl=2 l= 1 prim: INTEGER :00 - /// 7:d=1 hl=2 l= 13 cons: SEQUENCE - /// 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption - /// 20:d=2 hl=2 l= 0 prim: NULL - /// 22:d=1 hl=4 l=1769 prim: OCTET STRING [HEX DUMP]:3082...C813 - /// ``` - static let RSA_3072_PRIVATE = """ - -----BEGIN PRIVATE KEY----- - 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 - 9QS5ykVryo8URNisVCornefIEw== - -----END PRIVATE KEY----- - """ - - - /// RSA 4096 Private Key - /// - /// openssl asn1parse -i -in rsa_4096_priv.pem - /// ``` - /// 0:d=0 hl=4 l=2370 cons: SEQUENCE - /// 4:d=1 hl=2 l= 1 prim: INTEGER :00 - /// 7:d=1 hl=2 l= 13 cons: SEQUENCE - /// 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption - /// 20:d=2 hl=2 l= 0 prim: NULL - /// 22:d=1 hl=4 l=2348 prim: OCTET STRING [HEX DUMP]:3082...B4EA - /// ``` - static let RSA_4096_PRIVATE = """ - -----BEGIN PRIVATE KEY----- - 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 - PgBeOgkLlpYxcq87zFpg5qyHdq+06g== - -----END PRIVATE KEY----- - """ - - /// An encrypted RSA 1024 private key and it's original unencrypted pem file for testing AES CBC PBKDF2 decryption of PEM files... - /// - /// To decrypt an encrypted private RSA key... - /// 1) Strip the headers of the PEM and base64 decode the data - /// 2) Parse the data via ASN1 looking for the encryption algo, salt, iv and itterations used, and the ciphertext (aka octet string) - /// 3) Derive the encryption key using PBKDF2 (sha1, salt and itterations) - /// 4) Use encryption key to instantiate the AES CBC Cipher along with the IV - /// 5) Decrypt the encrypted octet string - /// 6) The decrypted octet string can be ASN1 parsed again for the private key octet string - /// 7) This raw data can be used to instantiate a SecKey - struct RSA_1024_PRIVATE_ENCRYPTED_PAIR { - /// An unencrypted RSA 1024 Private Key - /// - /// Generated with - /// ``` - /// openssl genpkey -algorithm RSA - /// -pkeyopt rsa_keygen_bits:1024 - /// -pkeyopt rsa_keygen_pubexp:65537 - /// -out foo.pem - /// ``` - static let UNENCRYPTED = """ - -----BEGIN PRIVATE KEY----- - MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMrTsyVLP/Ureyqm - zJDcolbO9cafCafeGXHrWJ4ar6QL+tT/apk+6kkgqvRU4QpJFurbzDXhmLpiUk9u - t2Oy6lw0LrF7Nz/XGHXfNHutLS6+jrHI+9x55l87CQyObsdaTt1jhP3IHp6FIA/S - rAAiCrFiPG7L97OdqREa2uWYIrupAgMBAAECgYAigSMvy/5kafI5Dkkst6wSUoDz - Oij9WsY/YAciVm3c3YDdbVooGdDngdwzVqE2C7sPVzcFT4yY4JMaGj6ugkhl+2mm - 8BP6GkOGYbwrMgyjPXLjg4mmeQS75NxxzVFcGxM3405G4p833DxNJyFZyJpfA0b6 - 5qhn4J2ZrxTwGu/TxQJBAPUxawoM1E3kRrJ+l30zHLVu0cbS4yXCYD24a9cWy6GI - aSNnJAzsb5eGkfg7epKNIov/sTh5RLeUu9x6d3Xe0qcCQQDTxEDSmBqdB0GhQF/9 - 7JXVdS25WEB4vJ/eVPPMDSoSS6IAR3+noVpQuLXqdIrAPA6alTsX1oxEKl6M6hTQ - 0lkvAkA9t2Kp9PC7amohI5wd92+Se4Jx+UMTjgmLf5AlY6d90UglkSCR4DF2gnjb - cp03pi677nA9NskFLHrc1DadhKihAkAE443/jqVmpKk+OMc+jHy1Ddx9X+01HF2w - e1OZjWBAReC6kuv+iboVDP6eKAyf/YL0zKctmLVqSXQfWrQaUhDfAkBNmxhdcL3M - 18PnvSVbfuwhKuNQd3lf8Xpr9eSHOnpYglqAbLObNHqZN24v+MI5M6Rdp6+yXryE - vcUs0rZnDXkl - -----END PRIVATE KEY----- - """ - - /// The encrypted version of the RSA 1024 Private Key - /// - /// Encrypted with - /// ``` - /// openssl pkcs8 - /// -in foo.pem - /// -topk8 - /// -v2 aes-128-cbc - /// -passout pass:mypassword - /// ``` - static let ENCRYPTED = """ - -----BEGIN ENCRYPTED PRIVATE KEY----- - MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQI49PtP+7yJmgCAggA - MB0GCWCGSAFlAwQBAgQQYz/oWtq4qhWPNrAQiO3i5wSCAoCjWvOSqAMdA4qDF8BB - aaqGRnZ/Lvewsrs4keppFogFnYpeVkzEmeleQLIYkO2mnNvsjhfh2Vk1LW/qNPIl - NvwjXyNbP1E6TlLmTNEAgIfyViHOCuk+17tkgAtK98huFTi0U+LbMcaxSnJ7CsNY - 9JODko7fLXMpEaGy5qcuXWsMHG1iKcggYs0J1kmWSVw9ZQP7Uh9hs31zz60kFe+T - 1I8EOjC06EcKY2HmOhzS+p378nWD3Lxi49FWkHslx1OtQwAXqMG5xWSo+kTWgmUx - fB3Olmv7opDcQ5OtOSxRjM/6SCtrtIlPRjIS7Uu4foW2BpFS+mkkvaJR0lMiEFjA - qMdLu3MZzT8U9lEDpd+ki+OjIC2bOXkv/OgHFmHjrTrGTVnK+HP5B0XkcaN0kmi5 - ypd8/XB4zDqO/eSSTKnDe5cvw9Ruj5vt9cesUGjckTlVlZ7Sip2nqtngEAh0k7gc - p8p0LpNRyOM5edxNCsRLWj3Z9oskkbEFbL3INuVr6HZ5C1IpUHaxzdii1FBeLSqY - RYCC7iOgfqRILkBN2dsnWhdLLvcVpeQqSccnNCYSrXgr40T8BqZKLnuhHT7/iZaw - OiKp9MyygPf0wO5IFaSglpk02dohJpg/LYxFBZk+qJKPR9883NrtSPSzXxDogu2f - /tc8OCoH919cB8WAsU1cvKYMxsr9HTfoxS7itrJX9d7tE3J2Ky7fQrPWt247BXSE - FMUJ8BQpLL/2lNIxW9clLEuzr0RZKu3AhBU0V0o8KDucrsLPdbLvV9/J8+G8VJWB - DZjkXrHO2Oob0rOBtz0gnIF4TSwMWlI28OFWLwN3ByGeT0KcDN7SghLtDSyEQKNW - ZHiA - -----END ENCRYPTED PRIVATE KEY----- - """ - } - - - // MARK: EC Keys - - /// EC P256 Public Key - /// - /// openssl asn1parse -i -in ec_256_pub.pem - /// ``` - /// 0:d=0 hl=2 l= 89 cons: SEQUENCE - /// 2:d=1 hl=2 l= 19 cons: SEQUENCE - /// 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey - /// 13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 - /// 23:d=1 hl=2 l= 66 prim: BIT STRING - /// ``` - static let EC_256_PUBLIC = """ - -----BEGIN PUBLIC KEY----- - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEb4nB0k8CBVnKCHVHkxuXAkSlZuO5 - Nsev1rzcRv5QHiJuWUKomFGadQlMSGwoDOHEDdW3ujcA6t0ADteHw6KrZg== - -----END PUBLIC KEY----- - """ - - /// EC P384 Public Key - /// - /// openssl asn1parse -i -in ec_384_pub.pem - /// ``` - /// 0:d=0 hl=2 l= 118 cons: SEQUENCE - /// 2:d=1 hl=2 l= 16 cons: SEQUENCE - /// 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey - /// 13:d=2 hl=2 l= 5 prim: OBJECT :secp384r1 - /// 20:d=1 hl=2 l= 98 prim: BIT STRING - /// ``` - static let EC_384_PUBLIC = """ - -----BEGIN PUBLIC KEY----- - MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEBwY0l7mq7hSBEZRld5ISWfSoFsYN3wwM - hdD3cMU95DmYXzbqVHB4dCfsy7bexm4h9c0zs4CyTPzy3DV3vfmv1akQJIQv7l08 - lx/YXNeGXTN4Gr9r4rwA5GvRl1p6plPL - -----END PUBLIC KEY----- - """ - - /// EC P521 Public Key - /// - /// openssl asn1parse -i -in ec_521_pub.pem - /// ``` - /// 0:d=0 hl=3 l= 155 cons: SEQUENCE - /// 3:d=1 hl=2 l= 16 cons: SEQUENCE - /// 5:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey - /// 14:d=2 hl=2 l= 5 prim: OBJECT :secp521r1 - /// 21:d=1 hl=3 l= 134 prim: BIT STRING - /// ``` - static let EC_521_PUBLIC = """ - -----BEGIN PUBLIC KEY----- - MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAp3v1UQWvSyQnkAUEBu+x/7ZrPtNJ - SCUk9kMvuZMyGP1idwvspALuJjzrSFFlXObjlOjxucSbWhTYF/o3nc0XzpAA3dxA - BYiMqH9vrVePoJMpv+DMdkUiUJ/WqHSOu9bJEi1h4fdqh5HHx4QZJY/iX/59VAi1 - uSbAhALvbdGFbVpkcOs= - -----END PUBLIC KEY----- - """ - - /// EC P256 Private Key - /// - /// openssl asn1parse -i -in ec_priv_256.pem - /// ``` - /// 0:d=0 hl=2 l= 119 cons: SEQUENCE - /// 2:d=1 hl=2 l= 1 prim: INTEGER :01 - /// 5:d=1 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:7C12DEBEED7417C33D239A4FFC7A036AAF5C51579469A7698931CEB8F5090507 - /// 39:d=1 hl=2 l= 10 cons: cont [ 0 ] - /// 41:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 - /// 51:d=1 hl=2 l= 68 cons: cont [ 1 ] - /// 53:d=2 hl=2 l= 66 prim: BIT STRING - /// ``` - static let EC_256_PRIVATE = """ - -----BEGIN EC PRIVATE KEY----- - MHcCAQEEIHwS3r7tdBfDPSOaT/x6A2qvXFFXlGmnaYkxzrj1CQUHoAoGCCqGSM49 - AwEHoUQDQgAE79HvsMQC9IyhZ7yCCYKmgz9zewM4KziWoVMXKN+7Cd5Ds+jK8V5q - hD6YVbbo/v1udmM5DfhHJiUW3Ww5++suRg== - -----END EC PRIVATE KEY----- - """ - - /// EC P384 Private Key - /// - /// openssl asn1parse -i -in ec_priv_384.pem - /// ``` - /// 0:d=0 hl=3 l= 164 cons: SEQUENCE - /// 3:d=1 hl=2 l= 1 prim: INTEGER :01 - /// 6:d=1 hl=2 l= 48 prim: OCTET STRING [HEX DUMP]:EB37EAA3BD6ED3A9C5EB2A54C56D23FC01D6EC21DAAF4408161E568189C3FB764C7E1CA42275289207644B5B28D2AECE - /// 56:d=1 hl=2 l= 7 cons: cont [ 0 ] - /// 58:d=2 hl=2 l= 5 prim: OBJECT :secp384r1 - /// 65:d=1 hl=2 l= 100 cons: cont [ 1 ] - /// 67:d=2 hl=2 l= 98 prim: BIT STRING - /// ``` - static let EC_384_PRIVATE = """ - -----BEGIN EC PRIVATE KEY----- - MIGkAgEBBDDrN+qjvW7TqcXrKlTFbSP8AdbsIdqvRAgWHlaBicP7dkx+HKQidSiS - B2RLWyjSrs6gBwYFK4EEACKhZANiAAQrRiaztGpInYo1XqMnNokWY6g1TcgMuzgq - Ug6LzFQbCAqCrcnM9+c9Z4/63dC06ulL/KbLQgThjSiqRzgbzvmOvB0OzlpX1weK - usFrF4Pi0B9pKPmVCAlSzaxVEmRsbmw= - -----END EC PRIVATE KEY----- - """ - - /// EC P521 Private Key - /// - /// openssl asn1parse -i -in ec_priv_521.pem - /// ``` - /// 0:d=0 hl=3 l= 219 cons: SEQUENCE - /// 3:d=1 hl=2 l= 1 prim: INTEGER :01 - /// 6:d=1 hl=2 l= 65 prim: OCTET STRING [HEX DUMP]:5A694D1575C8038BE99EEB94E7851A3DF80A1D715E4339F6E2F14B5E783A688D75B93DF90A5CD43EA89940C80D2756690996BC123A5A921FB5C6CC7B8E4EEFA777 - /// 73:d=1 hl=2 l= 7 cons: cont [ 0 ] - /// 75:d=2 hl=2 l= 5 prim: OBJECT :secp521r1 - /// 82:d=1 hl=3 l= 137 cons: cont [ 1 ] - /// 85:d=2 hl=3 l= 134 prim: BIT STRING - /// ``` - static let EC_521_PRIVATE = """ - -----BEGIN EC PRIVATE KEY----- - MIHbAgEBBEFaaU0VdcgDi+me65TnhRo9+AodcV5DOfbi8UteeDpojXW5PfkKXNQ+ - qJlAyA0nVmkJlrwSOlqSH7XGzHuOTu+nd6AHBgUrgQQAI6GBiQOBhgAEAZMhoDRn - GAeReuc4sKEq3fznP1rPZ4QDdwpNfxQbPLe0rzg4fk+J6BPlyQs74RfHtXxiHOiL - 3GZJLzo/pPbi96z7AG1AEABHWCcmi/uclGsjg0wNuKuWHwY8bJGvHZIBtd+px5+L - 6L0wg93uMy3o2nMEJd01n18LGvjdl3GUvgq2kXQN - -----END EC PRIVATE KEY----- - """ - - struct SECP256k1_KeyPair { - /// Can be derived from the PRIVATE Key - static let PUBLIC = """ - -----BEGIN PUBLIC KEY----- - MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzw - xDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== - -----END PUBLIC KEY----- - """ - - /// Should be able to derive the PUBLIC key - static let PRIVATE = """ - -----BEGIN EC PRIVATE KEY----- - MHQCAQEEIJmbpwD3mZhlEtiGzmgropJ/nSewc8UPyBE9wib742saoAcGBSuBBAAK - oUQDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwf - X7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== - -----END EC PRIVATE KEY----- - """ - } - - struct Ed25519_KeyPair { - /// Can be derived from the PRIVATE Key - static let PUBLIC = """ - -----BEGIN PUBLIC KEY----- - MCowBQYDK2VwAyEACM3Nzttt7KmXG9qDEYys++oQ9G749jqrbRRs92BUzpA= - -----END PUBLIC KEY----- - """ - - /// Should be able to derive the PUBLIC key - static let PRIVATE = """ - -----BEGIN PRIVATE KEY----- - MC4CAQAwBQYDK2VwBCIEIOkK9EOHRqD5QueUrMZbia55UWpokoFpWco4r2GnRVZ+ - -----END PRIVATE KEY----- - """ - } - - // MARK: Certificates - - static let CERT_FACEBOOK = """ - -----BEGIN CERTIFICATE----- - MIIH5DCCBsygAwIBAgIQDACZt9eJyfZmJjF+vOp8HDANBgkqhkiG9w0BAQsFADBw - MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 - d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz - dXJhbmNlIFNlcnZlciBDQTAeFw0xNjEyMDkwMDAwMDBaFw0xODAxMjUxMjAwMDBa - MGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpN - ZW5sbyBQYXJrMRcwFQYDVQQKEw5GYWNlYm9vaywgSW5jLjEXMBUGA1UEAwwOKi5m - YWNlYm9vay5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASg8YyvpzmIaFsT - Vg4VFbSnRe8bx+WFPCsE1GWKMTEi6qOS7WSdumWB47YSdtizC0Xx/wooFJxP3HOp - s0ktoHbTo4IFSjCCBUYwHwYDVR0jBBgwFoAUUWj/kK8CB3U8zNllZGKiErhZcjsw - HQYDVR0OBBYEFMuYKIyhcufiMqmaPfINoYFWoRqLMIHHBgNVHREEgb8wgbyCDiou - ZmFjZWJvb2suY29tgg4qLmZhY2Vib29rLm5ldIIIKi5mYi5jb22CCyouZmJjZG4u - bmV0ggsqLmZic2J4LmNvbYIQKi5tLmZhY2Vib29rLmNvbYIPKi5tZXNzZW5nZXIu - Y29tgg4qLnh4LmZiY2RuLm5ldIIOKi54eS5mYmNkbi5uZXSCDioueHouZmJjZG4u - bmV0ggxmYWNlYm9vay5jb22CBmZiLmNvbYINbWVzc2VuZ2VyLmNvbTAOBgNVHQ8B - Af8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHUGA1UdHwRu - MGwwNKAyoDCGLmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZl - ci1nNS5jcmwwNKAyoDCGLmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWhh - LXNlcnZlci1nNS5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEF - BQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwgYMG - CCsGAQUFBwEBBHcwdTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu - Y29tME0GCCsGAQUFBzAChkFodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln - aUNlcnRTSEEySGlnaEFzc3VyYW5jZVNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAA - MIICsAYKKwYBBAHWeQIEAgSCAqAEggKcApoAdgCkuQmQtBhYFIe7E6LMZ3AKPDWY - BPkb37jjd80OyA3cEAAAAVjl02IEAAAEAwBHMEUCIQDvWFsUeqWE/xwIYcXPvbb5 - ExzfHBZTNwfnUf4RPO/lBgIgdOGmr0j7+u8/S+7tfFw71ZEjqpwJELl/sEFuQdPn - pwQBLwCsO5rtf6lnR1cVnm19V1Zy+dmBAJQem97/7KExO3V4LQAAAVjl02IoAAAE - AQEAYvnMV+BfP3Wrk4yFQE/Zx5WsjSabYOpLj1Tj5xFaoVoHdGqLCf/Hi+Vv0IRy - ePKFBCSW0+3eA589+WnCDMwcJlBYeZV8MlvHFZg3a66Uhx/OAvoetb0mCtUpnmIE - UwLX/eMNEvjg2qTH3/33ysCo2l25+/EcR8upF+2KIcmnk5WwaJzfq7cFPQc4Cvcz - mTHasJi/jmVaIaJ9HC50g3dx584TQX26lDLddF/Li4uEbJ7TSopnTzjQdWBtWbMF - h3bcfhFCKaqK2kIJV3bgup5HibEnZ2LPm6lekY072ZFCGM4QYc4ukqzou2JWCRmG - o0dMHJhnvQXpnIQGwATqCD4Q1AB2AFYUBpov18Ls0/XhvUSyPsdGdrm8mRFcwO+U - mFXWidDdAAABWOXTYrkAAAQDAEcwRQIgGhXXbwUO5bD4Ts/Q0gqZwUS2vl/A4Hem - k7ovxl82v9oCIQCbtkflDXbcunY4MAQCbKlnesPGc/nftA84xDhJpxFHWQB3AO5L - vbd1zmC64UJpH6vhnmajD35fsHLYgwDEe4l6qP3LAAABWOXTZBEAAAQDAEgwRgIh - AKubngQoa5Iak8eCOrffH7Xx3AP1NMb5pFw35nt2VSeRAiEA47Kq1UQcDXIEsV+W - nuPd9LM5kpdeu0+TiHKtTLRQr0swDQYJKoZIhvcNAQELBQADggEBADrNSsoonbj1 - YGjwy9t9wP9+kZBwrNMO2n5N5fQNhGawkEAX+lXlzgm3TqYlTNi6sCFbPBAErim3 - aMVlWuOlctgnjtAdmdWZ4qEONrBLHPGgukDJ3Uen/EC/gwK6KdBCb4Ttp6MMPY1c - hb/ciTLi3QUUU4h4OJWqUjvccBCDs/LydNjKWZZTxLJmxRSmfpyCU3uU2XHHMNlo - 8UTIlqZsOtdqhg7/Q/cvMDHDkcI/tqelmg0MD2H9KpcmAvVkwgjn+BVpv5HELl+0 - EP0UhYknI1B6LBecJuj7jI26eXZdX35CYkpI/SZA9KK+OYKHh6vCxKqnRZ9ZQUOj - XnIWKQeV5Hg= - -----END CERTIFICATE----- - """ -} - From ad65faea814ac93a0488c538025d08b56f151023 Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sat, 17 Sep 2022 23:21:40 -0700 Subject: [PATCH 39/52] Removed RSAPublicKeyImporter and Exporter dependencies --- Sources/LibP2PCrypto/Keys/Types/RSA/RSA+SecKey.swift | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+SecKey.swift b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+SecKey.swift index 7be1719..f89153d 100644 --- a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+SecKey.swift +++ b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+SecKey.swift @@ -9,8 +9,6 @@ import Foundation import Multibase import Security -//import RSAPublicKeyImporter -//import RSAPublicKeyExporter struct RSAPublicKey:CommonPublicKey { static var keyType: LibP2PCrypto.Keys.GenericKeyType { .rsa } @@ -46,8 +44,6 @@ struct RSAPublicKey:CommonPublicKey { guard objID.bytes == RSAPublicKey.primaryObjectIdentifier else { throw NSError(domain: "RSAPublicKey Invalid marshaled data", code: 0) } guard case .bitString(let bits) = nodes[1] else { throw NSError(domain: "RSAPublicKey Invalid marshaled data", code: 0) } try self.init(rawRepresentation: bits) - - //try self.init(rawRepresentation: try RSAPublicKeyImporter().fromSubjectPublicKeyInfo(data)) } var rawRepresentation: Data { @@ -60,9 +56,6 @@ struct RSAPublicKey:CommonPublicKey { ]) return Data(ASN1.Encoder.encode(asnNodes)) - - //try! RSAPublicKeyExporter().toSubjectPublicKeyInfo(self.key.rawRepresentation()) - //try! self.key.rawRepresentation() } func encrypt(data: Data) throws -> Data { From cef427210fb16cec98b46161c6ea28a5ad7b73ca Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sat, 17 Sep 2022 23:22:13 -0700 Subject: [PATCH 40/52] Updated to use CryptoSwift 1.6.0 Release API --- .../Keys/Types/RSA/RSA+CryptoSwift.swift | 238 ++++++++---------- 1 file changed, 109 insertions(+), 129 deletions(-) diff --git a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift index c51804a..bdaa3c2 100644 --- a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift +++ b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift @@ -15,7 +15,7 @@ struct RSAPublicKey:CommonPublicKey { /// RSA Object Identifier Bytes private static var RSA_OBJECT_IDENTIFIER = Array(arrayLiteral: 42, 134, 72, 134, 247, 13, 1, 1, 1) - /// The underlying SecKey that backs this struct + /// The underlying CryptoSwift RSA Key that backs this struct private let key:RSA fileprivate init(_ rsa:RSA) { @@ -24,25 +24,21 @@ struct RSAPublicKey:CommonPublicKey { init(rawRepresentation raw: Data) throws { let asn1 = try ASN1.Decoder.decode(data: raw) - + guard case .sequence(let params) = asn1 else { throw NSError(domain: "Invalid ASN1 Encoding -> \(asn1)", code: 0) } - + /// We have an objectID header.... if case .sequence(let objectID) = params.first { guard case .objectIdentifier(let oid) = objectID.first else { throw NSError(domain: "Invalid ASN1 Encoding -> No ObjectID", code: 0) } guard oid.bytes == RSAPublicKey.RSA_OBJECT_IDENTIFIER else { throw NSError(domain: "Invalid ASN1 Encoding -> ObjectID != Public RSA Key ID", code: 0) } guard case .bitString(let bits) = params.last else { throw NSError(domain: "Invalid ASN1 Encoding -> No BitString", code: 0) } - - guard case .sequence(let params2) = try ASN1.Decoder.decode(data: bits) else { throw NSError(domain: "Invalid ASN1 Encoding -> No PubKey Sequence", code: 0) } - guard case .integer(let n) = params2.first else { throw NSError(domain: "Invalid ASN1 Encoding -> No Modulus", code: 0) } - guard case .integer(let e) = params2.last else { throw NSError(domain: "Invalid ASN1 Encoding -> No Public Exponent", code: 0) } - - self.key = CryptoSwift.RSA(n: n.bytes, e: e.bytes) + + self.key = try CryptoSwift.RSA(rawRepresentation: bits) } else if params.count == 2, case .integer = params.first { /// We have a direct sequence of integers guard case .integer(let n) = params.first else { throw NSError(domain: "Invalid ASN1 Encoding -> No Modulus", code: 0) } guard case .integer(let e) = params.last else { throw NSError(domain: "Invalid ASN1 Encoding -> No Public Exponent", code: 0) } - + self.key = CryptoSwift.RSA(n: n.bytes, e: e.bytes) } else { throw NSError(domain: "Invalid RSA rawRepresentation", code: 0) @@ -53,21 +49,14 @@ struct RSAPublicKey:CommonPublicKey { try self.init(rawRepresentation: data) } - /// We return the ASN1 Encoded DER Representation of the public key because that's what the rewRepresentation of RSA SecKey return + /// We return the ASN1 Encoded DER Representation of the public key because that's what the rawRepresentation of RSA SecKey return var rawRepresentation: Data { - let mod = key.n.serialize() - let pubkeyAsnNode:ASN1.Node = - .sequence(nodes: [ - .integer(data: Data(CryptoSwift.RSA.zeroPad(n: mod.bytes, to: mod.count + 1))), - .integer(data: key.e.serialize()) - ]) - - let asnNodes:ASN1.Node = .sequence(nodes: [ + let asnNodes:ASN1.Node = try! .sequence(nodes: [ .sequence(nodes: [ - .objectIdentifier(data: Data(RSAPublicKey.RSA_OBJECT_IDENTIFIER)), + .objectIdentifier(data: Data(RSAPublicKey.primaryObjectIdentifier)), .null ]), - .bitString(data: Data(ASN1.Encoder.encode(pubkeyAsnNode))) + .bitString(data: self.key.externalRepresentation()) ]) return Data(ASN1.Encoder.encode(asnNodes)) @@ -110,13 +99,13 @@ struct RSAPrivateKey:CommonPrivateKey { internal init(keySize: Int) throws { switch keySize { case 1024: - self.key = CryptoSwift.RSA(keySize: keySize) + self.key = try CryptoSwift.RSA(keySize: keySize) case 2048: - self.key = CryptoSwift.RSA(keySize: keySize) + self.key = try CryptoSwift.RSA(keySize: keySize) case 3072: - self.key = CryptoSwift.RSA(keySize: keySize) + self.key = try CryptoSwift.RSA(keySize: keySize) case 4096: - self.key = CryptoSwift.RSA(keySize: keySize) + self.key = try CryptoSwift.RSA(keySize: keySize) default: throw NSError(domain: "Invalid RSA Key Bit Length. (Use one of 2048, 3072 or 4096)", code: 0) } @@ -128,14 +117,8 @@ struct RSAPrivateKey:CommonPrivateKey { /// Expects the ASN1 Encoding of the DER formatted RSA Private Key init(rawRepresentation raw: Data) throws { - guard case .sequence(let params) = try ASN1.Decoder.decode(data: raw) else { throw NSError(domain: "Invalid ASN1 Encoding -> No PrivKey Sequence", code: 0) } - // We check for 4 here because internally we can only marshal the first 4 integers at the moment... - guard params.count == 4 || params.count == 9 else { throw NSError(domain: "Invalid ASN1 Encoding -> Invalid Private RSA param count. Expected 9 got \(params.count)", code: 0) } - guard case .integer(let n) = params[1] else { throw NSError(domain: "Invalid ASN1 Encoding -> PrivKey No Modulus", code: 0) } - guard case .integer(let e) = params[2] else { throw NSError(domain: "Invalid ASN1 Encoding -> PrivKey No Public Exponent", code: 0) } - guard case .integer(let d) = params[3] else { throw NSError(domain: "Invalid ASN1 Encoding -> PrivKey No Private Exponent", code: 0) } - - self.key = RSA(n: n.bytes, e: e.bytes, d: d.bytes) + self.key = try RSA(rawRepresentation: raw) + guard self.key.d != nil else { throw NSError(domain: "Invalid Private Key", code: 0) } } init(marshaledData data: Data) throws { @@ -143,16 +126,8 @@ struct RSAPrivateKey:CommonPrivateKey { } var rawRepresentation: Data { - guard let d = key.d else { /*throw NSError(domain: "Not a valid private RSA Key", code: 0)*/ return Data() } - let mod = key.n.serialize() - let privkeyAsnNode:ASN1.Node = - .sequence(nodes: [ - .integer(data: Data( Array(arrayLiteral: 0x00) )), - .integer(data: Data(CryptoSwift.RSA.zeroPad(n: mod.bytes, to: mod.count + 1))), - .integer(data: key.e.serialize()), - .integer(data: d.serialize()) - ]) - return Data(ASN1.Encoder.encode(privkeyAsnNode)) + guard key.d != nil else { /*throw NSError(domain: "Not a valid private RSA Key", code: 0)*/ return Data() } + return try! self.key.externalRepresentation() } func derivePublicKey() throws -> CommonPublicKey { @@ -169,11 +144,10 @@ struct RSAPrivateKey:CommonPrivateKey { } public func marshal() throws -> Data { - throw NSError(domain: "CryptoSwift based RSA private keys don't support marshaling", code: 0) - //var privateKey = PrivateKey() - //privateKey.type = .rsa - //privateKey.data = self.rawRepresentation - //return try privateKey.serializedData() + var privateKey = PrivateKey() + privateKey.type = .rsa + privateKey.data = self.rawRepresentation + return try privateKey.serializedData() } } @@ -196,14 +170,17 @@ extension CryptoSwift.RSA { /// - Note: The signature uses the SHA256 PKCS#1v15 Padding Scheme /// - Note: [EMSA-PKCS1-v1_5](https://datatracker.ietf.org/doc/html/rfc8017#section-9.2) fileprivate static func sign(message:Data, withKey key:RSA) throws -> Data { - guard let d = key.d else { throw NSError(domain: "Signing data requires a Private RSA key", code: 0) } - let encodedMessage = try CryptoSwift.RSA.hashedAndPKCSEncoded(message.bytes, modLength: key.n.serialize().count) - let n = BigUInteger(Data(encodedMessage)) - let e = d - let m = key.n - let signedData_RsaKey = CryptoSwift.RSA.modPow(n: n, e: e, m: m).serialize() - return signedData_RsaKey + return try Data(key.sign(message.bytes, variant: .message_pkcs1v15_SHA256)) + +// guard let d = key.d else { throw NSError(domain: "Signing data requires a Private RSA key", code: 0) } +// let encodedMessage = try CryptoSwift.RSA.hashedAndPKCSEncoded(message.bytes, modLength: key.n.serialize().count) +// +// let n = BigUInteger(Data(encodedMessage)) +// let e = d +// let m = key.n +// let signedData_RsaKey = CryptoSwift.RSA.modPow(n: n, e: e, m: m).serialize() +// return signedData_RsaKey } /// Verifies a signature for the expected data @@ -211,94 +188,97 @@ extension CryptoSwift.RSA { /// - Note: This method assumes the signature was generated using the SHA256 PKCS#1v15 Padding Scheme /// - Note: [EMSA-PKCS1-v1_5](https://datatracker.ietf.org/doc/html/rfc8017#section-9.2) fileprivate static func verify(signature:Data, fromMessage message:Data, usingKey key:RSA) throws -> Bool { - let modLength = key.n.serialize().count - /// Step 1: Ensure the signature is the same length as the key's modulus - guard signature.count == modLength else { throw NSError(domain: "Invalid Signature Length", code: 0) } - - /// Step 2: 'Decrypt' the signature - let n = BigUInteger(signature) - let e = key.e - let m = key.n - let pkcsEncodedSHA256HashedMessage = CryptoSwift.RSA.modPow(n: n, e: e, m: m).serialize() - /// Step 3: Compare the 'decrypted' signature with the prepared / encoded expected message.... - let preparedExpectedMessage = try CryptoSwift.RSA.hashedAndPKCSEncoded(message.bytes, modLength: modLength).dropFirst() - - guard pkcsEncodedSHA256HashedMessage == preparedExpectedMessage else { return false } + return try key.verify(signature: signature.bytes, for: message.bytes, variant: .message_pkcs1v15_SHA256) - return true +// let modLength = key.n.serialize().count +// /// Step 1: Ensure the signature is the same length as the key's modulus +// guard signature.count == modLength else { throw NSError(domain: "Invalid Signature Length", code: 0) } +// +// /// Step 2: 'Decrypt' the signature +// let n = BigUInteger(signature) +// let e = key.e +// let m = key.n +// let pkcsEncodedSHA256HashedMessage = CryptoSwift.RSA.modPow(n: n, e: e, m: m).serialize() +// +// /// Step 3: Compare the 'decrypted' signature with the prepared / encoded expected message.... +// let preparedExpectedMessage = try CryptoSwift.RSA.hashedAndPKCSEncoded(message.bytes, modLength: modLength).dropFirst() +// +// guard pkcsEncodedSHA256HashedMessage == preparedExpectedMessage else { return false } +// +// return true } /// prepends the data with zero's until it reaches the specified length - fileprivate static func zeroPad(n:[UInt8], to:Int) -> [UInt8] { - var modulus = n - while modulus.count < to { - modulus.insert(0x00, at: 0) - } - return modulus - } +// fileprivate static func zeroPad(n:[UInt8], to:Int) -> [UInt8] { +// var modulus = n +// while modulus.count < to { +// modulus.insert(0x00, at: 0) +// } +// return modulus +// } /// Modular exponentiation /// /// - Credit: AttaSwift BigInt /// - Source: https://rosettacode.org/wiki/Modular_exponentiation#Swift - fileprivate static func modPow(n: T, e: T, m: T) -> T { - guard e != 0 else { - return 1 - } - - var res = T(1) - var base = n % m - var exp = e - - while true { - if exp & 1 == 1 { - res *= base - res %= m - } - - if exp == 1 { - return res - } - - exp /= 2 - base *= base - base %= m - } - } +// fileprivate static func modPow(n: T, e: T, m: T) -> T { +// guard e != 0 else { +// return 1 +// } +// +// var res = T(1) +// var base = n % m +// var exp = e +// +// while true { +// if exp & 1 == 1 { +// res *= base +// res %= m +// } +// +// if exp == 1 { +// return res +// } +// +// exp /= 2 +// base *= base +// base %= m +// } +// } /// Hashes and Encodes a message for signing and verifying /// /// - Note: [EMSA-PKCS1-v1_5](https://datatracker.ietf.org/doc/html/rfc8017#section-9.2) - fileprivate static func hashedAndPKCSEncoded(_ message:[UInt8], modLength:Int) throws -> Data { - /// 1. Apply the hash function to the message M to produce a hash - let hashedMessage = SHA2(variant: .sha256).calculate(for: message) - - /// 2. Encode the algorithm ID for the hash function and the hash value into an ASN.1 value of type DigestInfo - /// PKCS#1_15 DER Structure (OID == sha256WithRSAEncryption) - let asn:ASN1.Node = .sequence(nodes: [ - .sequence(nodes: [ - .objectIdentifier(data: Data(Array(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01))), - .null - ]), - .octetString(data: Data(hashedMessage)) - ]) - - let t = ASN1.Encoder.encode(asn) - - /// 3. If emLen < tLen + 11, output "intended encoded message lengthtoo short" and stop - if modLength < t.count + 11 { throw NSError(domain: "intended encoded message length too short", code: 0) } - - /// 4. Generate an octet string PS consisting of emLen - tLen - 3 - /// octets with hexadecimal value 0xff. The length of PS will be - /// at least 8 octets. - let r = modLength - t.count - 3 - let padding = [0x00, 0x01] + Array(repeating: 0xFF, count: r) + [0x00] - - /// 5. Concatenate PS, the DER encoding T, and other padding to form - /// the encoded message EM as EM = 0x00 || 0x01 || PS || 0x00 || T. - return Data(padding + t) - } +// fileprivate static func hashedAndPKCSEncoded(_ message:[UInt8], modLength:Int) throws -> Data { +// /// 1. Apply the hash function to the message M to produce a hash +// let hashedMessage = SHA2(variant: .sha256).calculate(for: message) +// +// /// 2. Encode the algorithm ID for the hash function and the hash value into an ASN.1 value of type DigestInfo +// /// PKCS#1_15 DER Structure (OID == sha256WithRSAEncryption) +// let asn:ASN1.Node = .sequence(nodes: [ +// .sequence(nodes: [ +// .objectIdentifier(data: Data(Array(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01))), +// .null +// ]), +// .octetString(data: Data(hashedMessage)) +// ]) +// +// let t = ASN1.Encoder.encode(asn) +// +// /// 3. If emLen < tLen + 11, output "intended encoded message lengthtoo short" and stop +// if modLength < t.count + 11 { throw NSError(domain: "intended encoded message length too short", code: 0) } +// +// /// 4. Generate an octet string PS consisting of emLen - tLen - 3 +// /// octets with hexadecimal value 0xff. The length of PS will be +// /// at least 8 octets. +// let r = modLength - t.count - 3 +// let padding = [0x00, 0x01] + Array(repeating: 0xFF, count: r) + [0x00] +// +// /// 5. Concatenate PS, the DER encoding T, and other padding to form +// /// the encoded message EM as EM = 0x00 || 0x01 || PS || 0x00 || T. +// return Data(padding + t) +// } } #endif From 8f8fec7316911176383c8899ced8492802009b9e Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sat, 17 Sep 2022 23:35:33 -0700 Subject: [PATCH 41/52] Added link --- Tests/LibP2PCryptoTests/FixtureGenerationTests.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/LibP2PCryptoTests/FixtureGenerationTests.swift b/Tests/LibP2PCryptoTests/FixtureGenerationTests.swift index e9aee1d..4ec9733 100644 --- a/Tests/LibP2PCryptoTests/FixtureGenerationTests.swift +++ b/Tests/LibP2PCryptoTests/FixtureGenerationTests.swift @@ -205,6 +205,7 @@ static let {{KEY_TYPE}}{{KEY_SIZE}} = Fixture( return secKey } + /// https://datatracker.ietf.org/doc/html/rfc8017#section-9.1 private func sign(message: Data, using key: SecKey) throws -> [String] { let algorithms: [SecKeyAlgorithm] = [ .rsaSignatureRaw, From 5617dbbbd61d5f92957a5980b4e1afa1c2113efd Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sat, 17 Sep 2022 23:40:54 -0700 Subject: [PATCH 42/52] Added Marshaled and PEM Test Fixtures --- Tests/LibP2PCryptoTests/Marshaled.swift | 46 ++ Tests/LibP2PCryptoTests/Pem.swift | 586 ++++++++++++++++++++++++ 2 files changed, 632 insertions(+) create mode 100644 Tests/LibP2PCryptoTests/Marshaled.swift create mode 100644 Tests/LibP2PCryptoTests/Pem.swift diff --git a/Tests/LibP2PCryptoTests/Marshaled.swift b/Tests/LibP2PCryptoTests/Marshaled.swift new file mode 100644 index 0000000..c9c6cd6 --- /dev/null +++ b/Tests/LibP2PCryptoTests/Marshaled.swift @@ -0,0 +1,46 @@ +// +// marshaled.swift +// +// Created by Brandon Toms on 5/1/22. +// + +import Foundation + +/// Base64 Padded +struct MarshaledData { + /// A marshaled (base64padded) private 1024bit RSA key + /// + /// - Note: Generated via SecKey in swift-libp2p v0.1.0 + static let PRIVATE_RSA_KEY_1024 = "CAAS4AQwggJcAgEAAoGBAN2RGr5akx6ZTvpr3lZfSBU2YAo8s9Zu9B3XQcSjQPZyFTr3c3+XAJDIkpwSaXuc2EUdGP2yxzkShAt1hnibwESVV6lXtomB9mfIdvlh7J4Y1kP9wwF1KedTP4MNlVvaHZ7K+/5lyp+GObNAJJU/YnY/kz6kwUI7r0J948xDJdnlAgMBAAECgYB34EQ57UNf8M58StRWouKbJ3o6z7D1Ob62Tnp062cAb6Tw7GT/CTHzI7G+429Sw/93FVEqIgoL5OqwUHva0VnqP4dunGHHsG+KGwVqL0/6Sr/qkg9Mc3B7StI7QvFgnKQtzMlbFN6ijF0rGXaAh4gcnxzcJyT/KnxePbIyNOtfgQJBAPcbEmXbwIcPyT6QOwR8wwtDh+5GFSndJontFcd7ntC+6mqDuFaCpAd7yBeQcBOvHWOp/FbCBzJCEXFLWFcKgLECQQDlirT7AaujIMODtdBAG+Cxk62XmMX7AkD40Twn/URHJr91oUTJkZmLP6XjGR6kzRAeKfQr/3HpPnWx1uBBM9l1AkEAxD7rzZlIvfr7iIRjWpz7CecH/WQLSsQn50IzGcpDxuTYpt8Vdx8pxge4UX6UhA1++bf2f7B4pqFx2NhNwFLHAQJAMxgZCPZqOjmEy8CgxmRuM5jnvyLmjuUFiV0pws0BccUSQSDQqv2Z7AES7+YbiBuNRumXzGNj+8NHd3qZGGpuMQJAIgoySo2stOX3gTnlF5sPXFuiUjth3vhuzms15yeSqOs22Xew05TqVhoqYuWWjk1E2+Af5YAHKIbOEiVqSnzZEQ==" + /// A marshaled (base64padded) public 1024bit RSA key + /// + /// - Note: Generated via SecKey in swift-libp2p v0.1.0 + static let PUBLIC_RSA_KEY_1024 = "CAASogEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAN2RGr5akx6ZTvpr3lZfSBU2YAo8s9Zu9B3XQcSjQPZyFTr3c3+XAJDIkpwSaXuc2EUdGP2yxzkShAt1hnibwESVV6lXtomB9mfIdvlh7J4Y1kP9wwF1KedTP4MNlVvaHZ7K+/5lyp+GObNAJJU/YnY/kz6kwUI7r0J948xDJdnlAgMBAAE=" + + /// A marshaled (base64padded) private 2048bit RSA key + /// + /// - Note: I think this came from a GO or JS test fixture + static let PRIVATE_RSA_KEY_2048 = "CAASpgkwggSiAgEAAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAECggEAZtju/bcKvKFPz0mkHiaJcpycy9STKphorpCT83srBVQi59CdFU6Mj+aL/xt0kCPMVigJw8P3/YCEJ9J+rS8BsoWE+xWUEsJvtXoT7vzPHaAtM3ci1HZd302Mz1+GgS8Epdx+7F5p80XAFLDUnELzOzKftvWGZmWfSeDnslwVONkL/1VAzwKy7Ce6hk4SxRE7l2NE2OklSHOzCGU1f78ZzVYKSnS5Ag9YrGjOAmTOXDbKNKN/qIorAQ1bovzGoCwx3iGIatQKFOxyVCyO1PsJYT7JO+kZbhBWRRE+L7l+ppPER9bdLFxs1t5CrKc078h+wuUr05S1P1JjXk68pk3+kQKBgQDeK8AR11373Mzib6uzpjGzgNRMzdYNuExWjxyxAzz53NAR7zrPHvXvfIqjDScLJ4NcRO2TddhXAfZoOPVH5k4PJHKLBPKuXZpWlookCAyENY7+Pd55S8r+a+MusrMagYNljb5WbVTgN8cgdpim9lbbIFlpN6SZaVjLQL3J8TWH6wKBgQDSChzItkqWX11CNstJ9zJyUE20I7LrpyBJNgG1gtvz3ZMUQCn3PxxHtQzN9n1P0mSSYs+jBKPuoSyYLt1wwe10/lpgL4rkKWU3/m1Myt0tveJ9WcqHh6tzcAbb/fXpUFT/o4SWDimWkPkuCb+8j//2yiXk0a/T2f36zKMuZvujqQKBgC6B7BAQDG2H2B/ijofp12ejJU36nL98gAZyqOfpLJ+FeMz4TlBDQ+phIMhnHXA5UkdDapQ+zA3SrFk+6yGk9Vw4Hf46B+82SvOrSbmnMa+PYqKYIvUzR4gg34rL/7AhwnbEyD5hXq4dHwMNsIDq+l2elPjwm/U9V0gdAl2+r50HAoGALtsKqMvhv8HucAMBPrLikhXP/8um8mMKFMrzfqZ+otxfHzlhI0L08Bo3jQrb0Z7ByNY6M8epOmbCKADsbWcVre/AAY0ZkuSZK/CaOXNX/AhMKmKJh8qAOPRY02LIJRBCpfS4czEdnfUhYV/TYiFNnKRj57PPYZdTzUsxa/yVTmECgYBr7slQEjb5Onn5mZnGDh+72BxLNdgwBkhO0OCdpdISqk0F0Pxby22DFOKXZEpiyI9XYP1C8wPiJsShGm2yEwBPWXnrrZNWczaVuCbXHrZkWQogBDG3HGXNdU4MAWCyiYlyinIBpPpoAJZSzpGLmWbMWh28+RJS6AQX6KHrK1o2uw==" + /// A marshaled (base64padded) public 2048bit RSA key + /// + /// - Note: I think this came from a GO or JS test fixture + static let PUBLIC_RSA_KEY_2048 = "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAE=" + + /// A marshaled (base64padded) private 3072bit RSA key + /// + /// - Note: Generated via SecKey in swift-libp2p v0.1.0 + static let PRIVATE_RSA_KEY_3072 = "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" + /// A marshaled (base64padded) public 3072bit RSA key + /// + /// - Note: Generated via SecKey in swift-libp2p v0.1.0 + static let PUBLIC_RSA_KEY_3072 = "CAASpgMwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDZSv/m42dihS3dBZ6+265BQWgvCf5oPRwQieekWSpy14Zk+FaWAORry9/1X7HZYqTCrFNo9JUt9Qo9HDv//aGcIs6zhuSYNCy85hCBAUd/S9TTzx5qeimUZ1/Gm0VMPtpxUhZqt2V23/BcBFsUO40f0uibOA3BkftIMlNCJptlZ/cAlULFKs5bua6tEiWycuOrcbigvzrkbc/vDaRCOBPsLGOY/ljSpc74r75sEC9brbBPxMknpJ8o4YG/V1jo+t15WbILqPPEKm1m8RRuTZSeSOw1S/GlcD1c6HCeX9ms6kmA0LcOv/eSmHqiLCtXybOJFPxTvfbBlQyAwUf4gUj8HDrgfq9i6ldlEP6RfduBZPMvX7yEVDmoz1KtSX+usXC73gfwlZU9Rrwg8jkR9bl1G8c5J8nKiWIdxgq9HGY/CVVl9IsXf0m+0NNLEAClBIUbp9+7QH72wrnzcI6eAqAxMyUGcuqxcXQC4RMuCPE19eeUA4L+hbmyXzXAG+jMWDsCAwEAAQ==" + + /// A marshaled (base64padded) private 4096bit RSA key + /// + /// - Note: Generated via SecKey in swift-libp2p v0.1.0 + static let PRIVATE_RSA_KEY_4096 = "CAASqxIwggknAgEAAoICAQD3FcFG9iBVJA51KOMXlgDEeizTKBmJ25BpvX+RfhhDyl7NtEKO3WzidPuvpUngc39TmXbyN8ZlOCiMR7AOeRlBrcGgeeFXAljXUnwcGAnG8u19WeF8x64Xzl5I48i/hN/zxQ/YHGyyyvMOowh0s/XEmsbzZb8fmeRhkIeGt1DY16tAnewmV83Vn596yZHtA6RIAQMtcdCwVB0+DfZ+WPya3FHuTdVztmUzfKCatCUNr9NI4TXHgf+7BRu2idVbQ3khh/axAo+0c2htHs6b+AQ1rxZoEoB2f4YUL6ICj8zkJVC4pE1hraRMLR4ExPUb0mvy/DJq5T7+OcxO/Y/dskpsdyo0j00simHPeEmUuP45A7AbYTr7MKInMqlKBOLM+yORn8CDlKiT6cDkLD2oowUtf0wI8LK0D+fAg/5GwJtSg2uHRUWQFv19KkOUHuR8T/HYyGelBsKPZZ5O46BLD7PSYdTFHvNiURxOQKmZYeGhuBJ2wp0q6R+Evvdvwcu+PcGCQIuQb9mAdtHeS2oZjCxY+czsYy2pUHxxuGSpBI+aQLwRMFhpm0B/WMcjLOLFH88qNa7U8ksxZpLZufnBxuiqfX+FGKga3Jj7dv1oV+oFxTvndHhZL0JQDTylnuv79T1KYOVzxNWAJsaPXKUUbOhm4kdDHUY2RhEJMh2QVDitcwIDAQABAoICAH7z3ZfhVGGKoicOeAghWYmaILfpzZ1og/3gkNAnkr4aF7XnnZ8cJBsC8mKgMaIylcRVgKkZgUV2olbZaps1G4YEig0zMlXrbcxMpFom+7cOEHosmU/spQW0UftvljDZS9xLb0Wh7TO8VUA7Alg8MtXulLRwnc/V2WNLyGauf8q6nVIZEkHtMWRGnMGRGfpGub0JUCGkbg57WX8N2421mSzUcQBZW4gVuk/HBBoY30T2B0BV/rTglY35JPEYRtiahX12B4mRgFa+SXRvtMasmzUeHgwhHYJFKZXrl3lre2HpzlzghqXeeyFsuRTIQgwmhLKXZCxKV6B2AATCAY5uUhAAgqc1+gQ0YfP44HTGrokgVEdMazyW9ntTm/HsRQF62e9/pu6jJLnDrjOd+qa5gMC38n93zorD4DnCvOk3lKKl/FOevo74JHzEQd2nBc+uBYoJYs3VTnzib8nRZgj4qd0a9V66+oVoo5FPZMBvUMlkWO1dsXK1sZEu2MUUyXxj60ReZPaS8nFsz0LAjFpuv5bbqnnVp4vA9ToOcAVq0khU1VOOxszWKmJcn5i0M1ARyJc6oW5/cKjrcHeEI6ihs00XuuyFwewrEXQ5fOzAHiqc5RoRixTgEAqzCS9Vc52RqEQ6w3K8tDFAX0V92ARSoPGfLiXN59hTm96crmwtSYyRAoIBAQD8sqmwmYUfqx8Z9l3mcuDcOKo8eChMvSN9+unjJWbdSir3mnDuSmZ0r+rvacRR8kuQJGm5MTayAQL+sXC7KyjWdejItoX6MaZf4wyHFuscs9ksYdzdTHxOlmUQhpBqPUrDJSaeCSTJRfLkSpkSipyE/gg6hhhYkiYSV9nfGvDolf5kLoFNm4avrvKhLzJdldldN7UvYrRutj4SqiMEtltQlpWYD1HZra3fOk4IDDCBNCHI7eCKWTnknEYqtHj0CdYRKSxO5toG1sjnxBSSS/kH9RH+3V3RgKMvFPjjG8cs6+EhzQTQAerVLMUFj7MyCa5f5dKAIz5BlgISVIDY0ZWpAoIBAQD6UFDGMnSHs2y81iHiT0Fit7WAEDes6ZyfVMiDTbweFO0YczS3W1W9cVF0vBNMlarNjMkgk5ZE/tnHkuqe0A1ArULeMGfHJngvxGegDFfyYC/Fpcxbkx1iZbQv9Xwp1uqZOzwAppr09tfGynToz34CpEQmf3PDDcEzMEMewQBxAWUWnJAz3Vg+uBAPSitI4JSdkZPr+fW8uDpqitV4SFcoqo30Rf5woqKXBoQl6PgRSOUjyYeGCOiVSS+S/KjD0WPcIeMv3mMANsey4PA7UBKZtteZMRNSGj0ru2lySDJe05kDT8S4Jref6wRQ8cSubSrdmPgJizKfOJKK800cQGO7AoIBAA8zF+3dbhp3iolfPkqsQkY8ylCU0ae8ALSFMShOiZ9p5Ke8DGro4rzGEBWSgRKExnLHHezbvvR6BxoWxjcb43ry4Kuh/vELp3xBBfHiOQYi8z8uK8DL5vY7KZ0S2wDo6uROCcKbvjC1GmUM76Qj3kJJnWkXw8MgF1YnHp3C2xbCXujbuz9VyYYrucBkPF1QtCBdR3KwNzYplBY/UZfo+Bki1aCt2ziCr+CreyIUyZ4b6qRRWp43u7m6hKXw8Q2MwemKVnXwgNDEfpUiQDKEi1glL43q9sexOx+L3WSbuSFElugXkuCIHP3xkXBCMn8iAfEWu9ClTgtX4IwFtTJVePECggEAIW5yq1X3zFwBbOMomWI+eGHS4uzHkteMrJcVRLwwINBorjhM1SRkui2VVIL+DN98dYGVJz2u9z4WdhpALb/Z1UaOxMAwTB/uM2sG8BBV+rAwETTIq35lkUvGGhWuZKQopxiLNgcKcSc6wHkvzhxQVyf7Viz1mBqRMDYE8OmUFoO6LZ/xfovUimPo+THNwCkGkFjuKbkzweXVH3+1bSA0S+EjnnlutzpxfrxHEA0ifKSAvhvfdt5fufiRWw9VtvmTXcZE4pLQJCos185FJ5bVNSR/fR1Z2EBa5Sldtv6/g3y9VfzkaDf7lGc+J1VzEFzSOdCBaDzoIO3cXKSMKvbKmwKCAQBX2r42x+jAeolG41f5PqPHb20ZJyN00gqchYfZdb4nHDFPfcBdPYlKfOP4u7CaYDBmVcSiuzKfuaJDAdc/dirHW5CuHcyO+nBvYxov7tUFs6yaL4zpOsgwSODvXjry1J7ohbqiKy/KSHEvSl1pMpgEzt7XoPTN+W1QWcm/q3WB3WYXv2+p6APKoiwd0kB801+yRVsntb3grfHZxuxshszXWf2y4Fct6xHwjRfCX7nTb1GzYSOfXS4tWbvn50cGw7IY5VCfTUL7HX/H2b+k9ZG6jEut+uW3GsUdorQACwIkpT+ThcRHAykeVeDL1qRhGNL6flUGZzcwlDw+fOmGHqFR" + /// A marshaled (base64padded) public 4096bit RSA key + /// + /// - Note: Generated via SecKey in swift-libp2p v0.1.0 + static let PUBLIC_RSA_KEY_4096 = "CAASpgQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQD3FcFG9iBVJA51KOMXlgDEeizTKBmJ25BpvX+RfhhDyl7NtEKO3WzidPuvpUngc39TmXbyN8ZlOCiMR7AOeRlBrcGgeeFXAljXUnwcGAnG8u19WeF8x64Xzl5I48i/hN/zxQ/YHGyyyvMOowh0s/XEmsbzZb8fmeRhkIeGt1DY16tAnewmV83Vn596yZHtA6RIAQMtcdCwVB0+DfZ+WPya3FHuTdVztmUzfKCatCUNr9NI4TXHgf+7BRu2idVbQ3khh/axAo+0c2htHs6b+AQ1rxZoEoB2f4YUL6ICj8zkJVC4pE1hraRMLR4ExPUb0mvy/DJq5T7+OcxO/Y/dskpsdyo0j00simHPeEmUuP45A7AbYTr7MKInMqlKBOLM+yORn8CDlKiT6cDkLD2oowUtf0wI8LK0D+fAg/5GwJtSg2uHRUWQFv19KkOUHuR8T/HYyGelBsKPZZ5O46BLD7PSYdTFHvNiURxOQKmZYeGhuBJ2wp0q6R+Evvdvwcu+PcGCQIuQb9mAdtHeS2oZjCxY+czsYy2pUHxxuGSpBI+aQLwRMFhpm0B/WMcjLOLFH88qNa7U8ksxZpLZufnBxuiqfX+FGKga3Jj7dv1oV+oFxTvndHhZL0JQDTylnuv79T1KYOVzxNWAJsaPXKUUbOhm4kdDHUY2RhEJMh2QVDitcwIDAQAB" +} diff --git a/Tests/LibP2PCryptoTests/Pem.swift b/Tests/LibP2PCryptoTests/Pem.swift new file mode 100644 index 0000000..dc136fc --- /dev/null +++ b/Tests/LibP2PCryptoTests/Pem.swift @@ -0,0 +1,586 @@ +// +// pem.swift +// +// +// Created by Brandon Toms on 5/1/22. +// + +import Foundation + + +struct TestPEMKeys { + + // MARK: RSA Keys + + /// DER Format + static let RSA_1024_PUBLIC_DER = """ + -----BEGIN RSA PUBLIC KEY----- + MIGJAoGBANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXY + UMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE + 3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dV + ek9b9VAgMBAAE= + -----END RSA PUBLIC KEY----- + """ + + /// RSA 1024 Public Key + /// + /// openssl asn1parse -i -in rsa_1024_pub.pem + /// ``` + /// 0:d=0 hl=3 l= 159 cons: SEQUENCE + /// 3:d=1 hl=2 l= 13 cons: SEQUENCE + /// 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption + /// 16:d=2 hl=2 l= 0 prim: NULL + /// 18:d=1 hl=3 l= 141 prim: BIT STRING + /// ``` + static let RSA_1024_PUBLIC = """ + -----BEGIN PUBLIC KEY----- + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUkb0ol7/oLRbfbLqcW43xtJdh + 7xQ+Vf57DWtkEpeflZ5fUTIND+s1AlTAv63NsfUX3GJ/p+5jhnl3zweTKr7e5haM + ZqOJaARSKpGxOBwz1K3bhvJW+izXwUrwPbcmkiAlvkAsjj1hwRpND8t/NouF+hOw + HLQCPvkX8YLbUzoZrwIDAQAB + -----END PUBLIC KEY----- + """ + + /// RSA 2048 Public Key + /// + /// openssl asn1parse -i -in rsa_2048_pub.pem + /// ``` + /// 0:d=0 hl=4 l= 290 cons: SEQUENCE + /// 4:d=1 hl=2 l= 13 cons: SEQUENCE + /// 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption + /// 17:d=2 hl=2 l= 0 prim: NULL + /// 19:d=1 hl=4 l= 271 prim: BIT STRING + /// ``` + static let RSA_2048_PUBLIC = """ + -----BEGIN PUBLIC KEY----- + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxoLE8VNgeYQxGt5x++zW + 5INUrgTGhcrgEjDt8J78xAQ9UVZdya4q1PP79UPKb3xVvFHHAKQ2tEzzgpZvv2h8 + M/DCzvltWpsZwVx5lMiDA71xucRdF5Uiy5IiVdObIEswIN/x9AE21VJEqPihzPZf + AGKdpd8NkeaHnAnq4Pm5uJt9S+82U5iDQzufqm5S0YTTnmpmn6guCN7H2q9WENIi + D3mKxYzmDNyzxEhpS9jMKubvGM8p4dRSFFzQlWO1mIuO0Lf2QkgZsFMNNAEZg3ww + LP1OO288oXz8iAapfoLq3W+I2Jg4bOarHxSIvO2zSCZ1eagUCiHAtYfbWHAugoc5 + cQIDAQAB + -----END PUBLIC KEY----- + """ + + /// RSA 3072 Public Key + /// + /// openssl asn1parse -i -in rsa_3072_pub.pem + /// ``` + /// 0:d=0 hl=4 l= 418 cons: SEQUENCE + /// 4:d=1 hl=2 l= 13 cons: SEQUENCE + /// 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption + /// 17:d=2 hl=2 l= 0 prim: NULL + /// 19:d=1 hl=4 l= 399 prim: BIT STRING + /// ``` + static let RSA_3072_PUBLIC = """ + -----BEGIN PUBLIC KEY----- + MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0F50xB4o1O2y9Avm+YW2 + v9t5HHDI7kuWL/VxQE1R6FkpgLYQ0tUlB2QWGigYUhRS1f2ql1s7LXUVceUesHzH + oXlzmt3Rnow9doASPROlyAcNrzniMyDzH6hz2xaVsaj3Kygc9evQzuf1Rq1R0/bj + AkIlssumizfv70FZrmKBcgp5X9seC/wo3kWIRBV/Akx5vom0V6TEupy/39TDffnK + a3rN9yb7+ZGrHMoXofkd+pYATyIbuwsjeCU0F2v6+pbkXDrB0bgsp6/FRx8Tw9CF + gKf1JESSjeRQIk8nKXiqiNPmmOXvKH39lyEhWetcpn1E+bv7a4TAu1wy/FzLNp9w + NxB5zLX6gqxUDM0YUpsPMftB2dlixO0yzLcvbUohceIb03L4mBsvWfQ3W7yYkzBo + XTsPWofPw/jQY2IorGTKH4vgbQfW3fmqj1CXqgLEOe6XbWkcXyUnTp3Z24RiL5Ql + dqZJs8yEKZqNP9/miIS83Onc1zjWovT7LLFCnucNgoOHAgMBAAE= + -----END PUBLIC KEY----- + """ + + /// RSA 4096 Public Key + /// + /// openssl asn1parse -i -in rsa_4096_pub.pem + /// ``` + /// 0:d=0 hl=4 l= 546 cons: SEQUENCE + /// 4:d=1 hl=2 l= 13 cons: SEQUENCE + /// 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption + /// 17:d=2 hl=2 l= 0 prim: NULL + /// 19:d=1 hl=4 l= 527 prim: BIT STRING + /// ``` + static let RSA_4096_PUBLIC = """ + -----BEGIN PUBLIC KEY----- + MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA96lgFtImy0lK6uxopyli + o5WwN5FIxNdQXE6NL5o6t5Lwd3r/FCq+C1ix1Pb73lU0nJv64rCkgNn5U9rYv4e8 + /Eyu2Egp+2Ff1mBpPnNUU2oqe3de/cf8EyFR8+bQqS+cl5VSCOK2Bp87WlnjBBd7 + vy8UfjrDTIj63tNQADq/OkoUye9q7PPunTIVTvbRlC1vwVDPiCLIPUniRqAv44cG + qM1zxRMhJTEVWJhjnaMy/NJmJQPJvnsiED3aEi/uxsUaxhpKa6JfFL8doPbeydeb + 2NE+ynG6lCYjoqmSZU+9KSwaDtutV8U8LEP9B5cHS8thdyH7uFKjGt3kgD8bVtbT + UGL/zWWcPaqJktlM8iOh+arugW5C/fwZa1GkZZc2+Btq2MfEJ/8cSzp4nyQCk3ye + kCQPW+7wetbqadXMpvWHFQA3HHyPEdPFF4lImSH38c0WzTWaBpXeN5dcP1T5iY+Y + iQ7ZUSMrz8ImeYjAexHkVtE3uwaW77oBGJ33rwEXC0Agdo03mtQdKcEfB4l7gJ1G + Tg8KWPPK0bEHew+OZxiZRfrVnGRhPVGQ5w9Kuib6Q5tP8udsEgZIZUHftf7qdscU + kFc67jbydCj+HCD1Nvmja5u+GdJyQa021y2xbLINPaSTT1Ro8ttWRUM12Y4QEbuI + IwumfplSdLsojGNWVCpfxAsCAwEAAQ== + -----END PUBLIC KEY----- + """ + + /// RSA 1024 Private Key + /// + /// openssl asn1parse -i -in rsa_1024_priv.pem + /// ``` + /// 0:d=0 hl=4 l= 630 cons: SEQUENCE + /// 4:d=1 hl=2 l= 1 prim: INTEGER :00 + /// 7:d=1 hl=2 l= 13 cons: SEQUENCE + /// 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption + /// 20:d=2 hl=2 l= 0 prim: NULL + /// 22:d=1 hl=4 l= 608 prim: OCTET STRING [HEX DUMP]:3082...AA50 + /// ``` + static let RSA_1024_PRIVATE = """ + -----BEGIN PRIVATE KEY----- + MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANSRvSiXv+gtFt9s + upxbjfG0l2HvFD5V/nsNa2QSl5+Vnl9RMg0P6zUCVMC/rc2x9RfcYn+n7mOGeXfP + B5Mqvt7mFoxmo4loBFIqkbE4HDPUrduG8lb6LNfBSvA9tyaSICW+QCyOPWHBGk0P + y382i4X6E7ActAI++RfxgttTOhmvAgMBAAECgYAyjMnf+l5ft0FGNpQWFMunnBuX + 5YP54vdWifVs4eL+x1TXM/bkFlIH1BsVjz+kt9oiJ32g/+1364W9URVrEPI8nk5i + Id40q3Qiozvn4ceWtSoCGmuxIbdRqL1JJn5e8Zfzs7E8KZimYu00t2qcidFDUsEC + biCqT14UNcbpwsOpkQJBAPxMogs3OnkgCWlptZckjg+srwxnXIkzDhSO+WaKl2Dm + DvSMnB2Ws64EDu2dP+HLiuoyqG/ZqRabdQqIsIrkLpkCQQDXr+wYGoOiL26PrAew + z49aH/wQZq8fBM2yuwvR+ZDRraQ0otQV1aRwffqlI+IfYowJvyPX+EC/ftcff0qa + 6R+HAkAQZlrSJ9DhNrfl5j0rifDCDBOE1uMo9+yeYXzMsY2NeubV9p3fPoCHezQN + Nf+FCdoJxykzvA5Fre05thDjtllhAkEAgdsf2M81y1KlTQi0xKXiV8+D8dfwvUsm + EOJ+Vlfb8fGKOEqER/UNgNDIM96ryFuLll6m1ONZEDHskMERiLysRwJAawkNDlqe + sIjqrfR2luw+TLHkMI0T6pTY9s+79F9VVV/V13v2qtTpXw1eu7Sw+oDBpJoocz/h + +YzU+CyyzO+qUA== + -----END PRIVATE KEY----- + """ + + /// RSA 2048 Private Key + /// + /// openssl asn1parse -i -in rsa_2048_priv.pem + /// ``` + /// 0:d=0 hl=4 l=1214 cons: SEQUENCE + /// 4:d=1 hl=2 l= 1 prim: INTEGER :00 + /// 7:d=1 hl=2 l= 13 cons: SEQUENCE + /// 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption + /// 20:d=2 hl=2 l= 0 prim: NULL + /// 22:d=1 hl=4 l=1192 prim: OCTET STRING [HEX DUMP]:3082...59D7 + /// ``` + static let RSA_2048_PRIVATE = """ + -----BEGIN PRIVATE KEY----- + MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDGgsTxU2B5hDEa + 3nH77Nbkg1SuBMaFyuASMO3wnvzEBD1RVl3JrirU8/v1Q8pvfFW8UccApDa0TPOC + lm+/aHwz8MLO+W1amxnBXHmUyIMDvXG5xF0XlSLLkiJV05sgSzAg3/H0ATbVUkSo + +KHM9l8AYp2l3w2R5oecCerg+bm4m31L7zZTmINDO5+qblLRhNOeamafqC4I3sfa + r1YQ0iIPeYrFjOYM3LPESGlL2Mwq5u8Yzynh1FIUXNCVY7WYi47Qt/ZCSBmwUw00 + ARmDfDAs/U47bzyhfPyIBql+gurdb4jYmDhs5qsfFIi87bNIJnV5qBQKIcC1h9tY + cC6ChzlxAgMBAAECggEBAJvNVR+HbgfRvey1vEaa+4p8nUC7lMi7kyQT7RxW3FJI + dYvaOmApZ4qeOBmm7EKWFoBousUBHcJjRxguVGSpcBogE/X4hGCBrTQ7DV2+Bj4w + OQsxWFNDBP07o+Ey5OTyvkJ/Idp9/XhuSl9ITU2d7LBTtiHSsEbb5YGNsyCCP8bo + OP/PQZPDgXz9vLg674rPgm32cHPIWDomspJ34EkD/szyQOpW2AM99v3NbqovM8ie + T91266iPASTngGQG3qA54zJ91Ulu7kx+LNYpSknZOvWxrxDB8+oArdEZFuPpT5L6 + OKj5ICJCFRkiROE2xErn/nUmu4R1AA3WDnFZQMzGFAECgYEA5dDYyHUhtjlM13OL + hUoiBWk4yzz3wB/jcvvdq8OVU0nWeuTiZh4cPSDp67q4AAffAbJvsqYomyA/Eqt/ + NNZKE7ZP9a+KFXbyd1BtDgFiVEcNGNZ0K7beQEbVlG7sFN+s8YT7eeObBoXyhhPA + WC6fWcYfrZatCuNAmcjutoWCarECgYEA3SDViFs2Eb5II9DHwljNJF8gFgRJhAKj + bMEGUVgSK8WWQIO2ZdzlA1kV+U0S5FXx3zyQAWVqCkdAzFB4sZjmT47NZN4cvo30 + E32rXWDoNbKpljBvEhx2HUMA+Zpdpe/vZUHlNpqGT0MZaP6nPTg79EsBdiMvVC8l + 3UC7XW5f6sECgYA1AMzutq0WxPJnAnwcOrPMAa+amC4fvnsLyvEeK1amRfJUl7Nr + j+g9ZPjuaDsFrssNLiU6072rwW0qlikZe47MKxEX/etf9fYH9KGiSElwXI61ushC + SMPLmUqrGEYUrl3JujzxqL/Zak08BRQogmA4KUynEYhJaY49qaz8paAlkQKBgDer + U3avl84hvGGf5xprZsHYXOiODb/5NhFkCuYhqPlyFeCKCDpewRz1qY2ItM/dPzY3 + Nf3T/T03MP3+6FO1rY2r4tOZA12JuT/K7IBmrC8Qmpcf/GZv2eCGBNHR5e+nlvpD + +6OihVuhBd2j9pB3/sgCtgx60Sh9cifgawsbhXRBAoGBALXBsU6d6TRU0PTOwvos + zV4dWva41cuElT1hp4rzgSgRtUIbaFVpGi4STb/B3znvlE4VNsePgq2oe6c4Bx7l + JwZ4bU1ZvxWZ+tLdYnelwhfgq/14tjWPGvlE+bF7s1irJIHsTsoShF+RfavhqVXF + 6FyFEjB0XDmXjJgIxkenwlnX + -----END PRIVATE KEY----- + """ + + /// RSA 3072 Private Key + /// + /// openssl asn1parse -i -in rsa_3072_priv.pem + /// ``` + /// 0:d=0 hl=4 l=1791 cons: SEQUENCE + /// 4:d=1 hl=2 l= 1 prim: INTEGER :00 + /// 7:d=1 hl=2 l= 13 cons: SEQUENCE + /// 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption + /// 20:d=2 hl=2 l= 0 prim: NULL + /// 22:d=1 hl=4 l=1769 prim: OCTET STRING [HEX DUMP]:3082...C813 + /// ``` + static let RSA_3072_PRIVATE = """ + -----BEGIN PRIVATE KEY----- + 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 + 9QS5ykVryo8URNisVCornefIEw== + -----END PRIVATE KEY----- + """ + + + /// RSA 4096 Private Key + /// + /// openssl asn1parse -i -in rsa_4096_priv.pem + /// ``` + /// 0:d=0 hl=4 l=2370 cons: SEQUENCE + /// 4:d=1 hl=2 l= 1 prim: INTEGER :00 + /// 7:d=1 hl=2 l= 13 cons: SEQUENCE + /// 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption + /// 20:d=2 hl=2 l= 0 prim: NULL + /// 22:d=1 hl=4 l=2348 prim: OCTET STRING [HEX DUMP]:3082...B4EA + /// ``` + static let RSA_4096_PRIVATE = """ + -----BEGIN PRIVATE KEY----- + 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 + PgBeOgkLlpYxcq87zFpg5qyHdq+06g== + -----END PRIVATE KEY----- + """ + + /// An encrypted RSA 1024 private key and it's original unencrypted pem file for testing AES CBC PBKDF2 decryption of PEM files... + /// + /// To decrypt an encrypted private RSA key... + /// 1) Strip the headers of the PEM and base64 decode the data + /// 2) Parse the data via ASN1 looking for the encryption algo, salt, iv and itterations used, and the ciphertext (aka octet string) + /// 3) Derive the encryption key using PBKDF2 (sha1, salt and itterations) + /// 4) Use encryption key to instantiate the AES CBC Cipher along with the IV + /// 5) Decrypt the encrypted octet string + /// 6) The decrypted octet string can be ASN1 parsed again for the private key octet string + /// 7) This raw data can be used to instantiate a SecKey + struct RSA_1024_PRIVATE_ENCRYPTED_PAIR { + /// An unencrypted RSA 1024 Private Key + /// + /// Generated with + /// ``` + /// openssl genpkey -algorithm RSA + /// -pkeyopt rsa_keygen_bits:1024 + /// -pkeyopt rsa_keygen_pubexp:65537 + /// -out foo.pem + /// ``` + static let UNENCRYPTED = """ + -----BEGIN PRIVATE KEY----- + MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMrTsyVLP/Ureyqm + zJDcolbO9cafCafeGXHrWJ4ar6QL+tT/apk+6kkgqvRU4QpJFurbzDXhmLpiUk9u + t2Oy6lw0LrF7Nz/XGHXfNHutLS6+jrHI+9x55l87CQyObsdaTt1jhP3IHp6FIA/S + rAAiCrFiPG7L97OdqREa2uWYIrupAgMBAAECgYAigSMvy/5kafI5Dkkst6wSUoDz + Oij9WsY/YAciVm3c3YDdbVooGdDngdwzVqE2C7sPVzcFT4yY4JMaGj6ugkhl+2mm + 8BP6GkOGYbwrMgyjPXLjg4mmeQS75NxxzVFcGxM3405G4p833DxNJyFZyJpfA0b6 + 5qhn4J2ZrxTwGu/TxQJBAPUxawoM1E3kRrJ+l30zHLVu0cbS4yXCYD24a9cWy6GI + aSNnJAzsb5eGkfg7epKNIov/sTh5RLeUu9x6d3Xe0qcCQQDTxEDSmBqdB0GhQF/9 + 7JXVdS25WEB4vJ/eVPPMDSoSS6IAR3+noVpQuLXqdIrAPA6alTsX1oxEKl6M6hTQ + 0lkvAkA9t2Kp9PC7amohI5wd92+Se4Jx+UMTjgmLf5AlY6d90UglkSCR4DF2gnjb + cp03pi677nA9NskFLHrc1DadhKihAkAE443/jqVmpKk+OMc+jHy1Ddx9X+01HF2w + e1OZjWBAReC6kuv+iboVDP6eKAyf/YL0zKctmLVqSXQfWrQaUhDfAkBNmxhdcL3M + 18PnvSVbfuwhKuNQd3lf8Xpr9eSHOnpYglqAbLObNHqZN24v+MI5M6Rdp6+yXryE + vcUs0rZnDXkl + -----END PRIVATE KEY----- + """ + + /// The encrypted version of the RSA 1024 Private Key + /// + /// Encrypted with + /// ``` + /// openssl pkcs8 + /// -in foo.pem + /// -topk8 + /// -v2 aes-128-cbc + /// -passout pass:mypassword + /// ``` + static let ENCRYPTED = """ + -----BEGIN ENCRYPTED PRIVATE KEY----- + MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQI49PtP+7yJmgCAggA + MB0GCWCGSAFlAwQBAgQQYz/oWtq4qhWPNrAQiO3i5wSCAoCjWvOSqAMdA4qDF8BB + aaqGRnZ/Lvewsrs4keppFogFnYpeVkzEmeleQLIYkO2mnNvsjhfh2Vk1LW/qNPIl + NvwjXyNbP1E6TlLmTNEAgIfyViHOCuk+17tkgAtK98huFTi0U+LbMcaxSnJ7CsNY + 9JODko7fLXMpEaGy5qcuXWsMHG1iKcggYs0J1kmWSVw9ZQP7Uh9hs31zz60kFe+T + 1I8EOjC06EcKY2HmOhzS+p378nWD3Lxi49FWkHslx1OtQwAXqMG5xWSo+kTWgmUx + fB3Olmv7opDcQ5OtOSxRjM/6SCtrtIlPRjIS7Uu4foW2BpFS+mkkvaJR0lMiEFjA + qMdLu3MZzT8U9lEDpd+ki+OjIC2bOXkv/OgHFmHjrTrGTVnK+HP5B0XkcaN0kmi5 + ypd8/XB4zDqO/eSSTKnDe5cvw9Ruj5vt9cesUGjckTlVlZ7Sip2nqtngEAh0k7gc + p8p0LpNRyOM5edxNCsRLWj3Z9oskkbEFbL3INuVr6HZ5C1IpUHaxzdii1FBeLSqY + RYCC7iOgfqRILkBN2dsnWhdLLvcVpeQqSccnNCYSrXgr40T8BqZKLnuhHT7/iZaw + OiKp9MyygPf0wO5IFaSglpk02dohJpg/LYxFBZk+qJKPR9883NrtSPSzXxDogu2f + /tc8OCoH919cB8WAsU1cvKYMxsr9HTfoxS7itrJX9d7tE3J2Ky7fQrPWt247BXSE + FMUJ8BQpLL/2lNIxW9clLEuzr0RZKu3AhBU0V0o8KDucrsLPdbLvV9/J8+G8VJWB + DZjkXrHO2Oob0rOBtz0gnIF4TSwMWlI28OFWLwN3ByGeT0KcDN7SghLtDSyEQKNW + ZHiA + -----END ENCRYPTED PRIVATE KEY----- + """ + } + + + // MARK: EC Keys + + /// EC P256 Public Key + /// + /// openssl asn1parse -i -in ec_256_pub.pem + /// ``` + /// 0:d=0 hl=2 l= 89 cons: SEQUENCE + /// 2:d=1 hl=2 l= 19 cons: SEQUENCE + /// 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey + /// 13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 + /// 23:d=1 hl=2 l= 66 prim: BIT STRING + /// ``` + static let EC_256_PUBLIC = """ + -----BEGIN PUBLIC KEY----- + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEb4nB0k8CBVnKCHVHkxuXAkSlZuO5 + Nsev1rzcRv5QHiJuWUKomFGadQlMSGwoDOHEDdW3ujcA6t0ADteHw6KrZg== + -----END PUBLIC KEY----- + """ + + /// EC P384 Public Key + /// + /// openssl asn1parse -i -in ec_384_pub.pem + /// ``` + /// 0:d=0 hl=2 l= 118 cons: SEQUENCE + /// 2:d=1 hl=2 l= 16 cons: SEQUENCE + /// 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey + /// 13:d=2 hl=2 l= 5 prim: OBJECT :secp384r1 + /// 20:d=1 hl=2 l= 98 prim: BIT STRING + /// ``` + static let EC_384_PUBLIC = """ + -----BEGIN PUBLIC KEY----- + MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEBwY0l7mq7hSBEZRld5ISWfSoFsYN3wwM + hdD3cMU95DmYXzbqVHB4dCfsy7bexm4h9c0zs4CyTPzy3DV3vfmv1akQJIQv7l08 + lx/YXNeGXTN4Gr9r4rwA5GvRl1p6plPL + -----END PUBLIC KEY----- + """ + + /// EC P521 Public Key + /// + /// openssl asn1parse -i -in ec_521_pub.pem + /// ``` + /// 0:d=0 hl=3 l= 155 cons: SEQUENCE + /// 3:d=1 hl=2 l= 16 cons: SEQUENCE + /// 5:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey + /// 14:d=2 hl=2 l= 5 prim: OBJECT :secp521r1 + /// 21:d=1 hl=3 l= 134 prim: BIT STRING + /// ``` + static let EC_521_PUBLIC = """ + -----BEGIN PUBLIC KEY----- + MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAp3v1UQWvSyQnkAUEBu+x/7ZrPtNJ + SCUk9kMvuZMyGP1idwvspALuJjzrSFFlXObjlOjxucSbWhTYF/o3nc0XzpAA3dxA + BYiMqH9vrVePoJMpv+DMdkUiUJ/WqHSOu9bJEi1h4fdqh5HHx4QZJY/iX/59VAi1 + uSbAhALvbdGFbVpkcOs= + -----END PUBLIC KEY----- + """ + + /// EC P256 Private Key + /// + /// openssl asn1parse -i -in ec_priv_256.pem + /// ``` + /// 0:d=0 hl=2 l= 119 cons: SEQUENCE + /// 2:d=1 hl=2 l= 1 prim: INTEGER :01 + /// 5:d=1 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:7C12DEBEED7417C33D239A4FFC7A036AAF5C51579469A7698931CEB8F5090507 + /// 39:d=1 hl=2 l= 10 cons: cont [ 0 ] + /// 41:d=2 hl=2 l= 8 prim: OBJECT :prime256v1 + /// 51:d=1 hl=2 l= 68 cons: cont [ 1 ] + /// 53:d=2 hl=2 l= 66 prim: BIT STRING + /// ``` + static let EC_256_PRIVATE = """ + -----BEGIN EC PRIVATE KEY----- + MHcCAQEEIHwS3r7tdBfDPSOaT/x6A2qvXFFXlGmnaYkxzrj1CQUHoAoGCCqGSM49 + AwEHoUQDQgAE79HvsMQC9IyhZ7yCCYKmgz9zewM4KziWoVMXKN+7Cd5Ds+jK8V5q + hD6YVbbo/v1udmM5DfhHJiUW3Ww5++suRg== + -----END EC PRIVATE KEY----- + """ + + /// EC P384 Private Key + /// + /// openssl asn1parse -i -in ec_priv_384.pem + /// ``` + /// 0:d=0 hl=3 l= 164 cons: SEQUENCE + /// 3:d=1 hl=2 l= 1 prim: INTEGER :01 + /// 6:d=1 hl=2 l= 48 prim: OCTET STRING [HEX DUMP]:EB37EAA3BD6ED3A9C5EB2A54C56D23FC01D6EC21DAAF4408161E568189C3FB764C7E1CA42275289207644B5B28D2AECE + /// 56:d=1 hl=2 l= 7 cons: cont [ 0 ] + /// 58:d=2 hl=2 l= 5 prim: OBJECT :secp384r1 + /// 65:d=1 hl=2 l= 100 cons: cont [ 1 ] + /// 67:d=2 hl=2 l= 98 prim: BIT STRING + /// ``` + static let EC_384_PRIVATE = """ + -----BEGIN EC PRIVATE KEY----- + MIGkAgEBBDDrN+qjvW7TqcXrKlTFbSP8AdbsIdqvRAgWHlaBicP7dkx+HKQidSiS + B2RLWyjSrs6gBwYFK4EEACKhZANiAAQrRiaztGpInYo1XqMnNokWY6g1TcgMuzgq + Ug6LzFQbCAqCrcnM9+c9Z4/63dC06ulL/KbLQgThjSiqRzgbzvmOvB0OzlpX1weK + usFrF4Pi0B9pKPmVCAlSzaxVEmRsbmw= + -----END EC PRIVATE KEY----- + """ + + /// EC P521 Private Key + /// + /// openssl asn1parse -i -in ec_priv_521.pem + /// ``` + /// 0:d=0 hl=3 l= 219 cons: SEQUENCE + /// 3:d=1 hl=2 l= 1 prim: INTEGER :01 + /// 6:d=1 hl=2 l= 65 prim: OCTET STRING [HEX DUMP]:5A694D1575C8038BE99EEB94E7851A3DF80A1D715E4339F6E2F14B5E783A688D75B93DF90A5CD43EA89940C80D2756690996BC123A5A921FB5C6CC7B8E4EEFA777 + /// 73:d=1 hl=2 l= 7 cons: cont [ 0 ] + /// 75:d=2 hl=2 l= 5 prim: OBJECT :secp521r1 + /// 82:d=1 hl=3 l= 137 cons: cont [ 1 ] + /// 85:d=2 hl=3 l= 134 prim: BIT STRING + /// ``` + static let EC_521_PRIVATE = """ + -----BEGIN EC PRIVATE KEY----- + MIHbAgEBBEFaaU0VdcgDi+me65TnhRo9+AodcV5DOfbi8UteeDpojXW5PfkKXNQ+ + qJlAyA0nVmkJlrwSOlqSH7XGzHuOTu+nd6AHBgUrgQQAI6GBiQOBhgAEAZMhoDRn + GAeReuc4sKEq3fznP1rPZ4QDdwpNfxQbPLe0rzg4fk+J6BPlyQs74RfHtXxiHOiL + 3GZJLzo/pPbi96z7AG1AEABHWCcmi/uclGsjg0wNuKuWHwY8bJGvHZIBtd+px5+L + 6L0wg93uMy3o2nMEJd01n18LGvjdl3GUvgq2kXQN + -----END EC PRIVATE KEY----- + """ + + struct SECP256k1_KeyPair { + /// Can be derived from the PRIVATE Key + static let PUBLIC = """ + -----BEGIN PUBLIC KEY----- + MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzw + xDevjsbU1gOhdju+FQZaALwfX7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== + -----END PUBLIC KEY----- + """ + + /// Should be able to derive the PUBLIC key + static let PRIVATE = """ + -----BEGIN EC PRIVATE KEY----- + MHQCAQEEIJmbpwD3mZhlEtiGzmgropJ/nSewc8UPyBE9wib742saoAcGBSuBBAAK + oUQDQgAEIgC+scMFLUBdd3OlModp6SbEaBGrHyzwxDevjsbU1gOhdju+FQZaALwf + X7XmsHhKFFNYpVS0GXhMMzzFf1Ld7w== + -----END EC PRIVATE KEY----- + """ + } + + struct Ed25519_KeyPair { + /// Can be derived from the PRIVATE Key + static let PUBLIC = """ + -----BEGIN PUBLIC KEY----- + MCowBQYDK2VwAyEACM3Nzttt7KmXG9qDEYys++oQ9G749jqrbRRs92BUzpA= + -----END PUBLIC KEY----- + """ + + /// Should be able to derive the PUBLIC key + static let PRIVATE = """ + -----BEGIN PRIVATE KEY----- + MC4CAQAwBQYDK2VwBCIEIOkK9EOHRqD5QueUrMZbia55UWpokoFpWco4r2GnRVZ+ + -----END PRIVATE KEY----- + """ + } + + // MARK: Certificates + + static let CERT_FACEBOOK = """ + -----BEGIN CERTIFICATE----- + MIIH5DCCBsygAwIBAgIQDACZt9eJyfZmJjF+vOp8HDANBgkqhkiG9w0BAQsFADBw + MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 + d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz + dXJhbmNlIFNlcnZlciBDQTAeFw0xNjEyMDkwMDAwMDBaFw0xODAxMjUxMjAwMDBa + MGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRMwEQYDVQQHEwpN + ZW5sbyBQYXJrMRcwFQYDVQQKEw5GYWNlYm9vaywgSW5jLjEXMBUGA1UEAwwOKi5m + YWNlYm9vay5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASg8YyvpzmIaFsT + Vg4VFbSnRe8bx+WFPCsE1GWKMTEi6qOS7WSdumWB47YSdtizC0Xx/wooFJxP3HOp + s0ktoHbTo4IFSjCCBUYwHwYDVR0jBBgwFoAUUWj/kK8CB3U8zNllZGKiErhZcjsw + HQYDVR0OBBYEFMuYKIyhcufiMqmaPfINoYFWoRqLMIHHBgNVHREEgb8wgbyCDiou + ZmFjZWJvb2suY29tgg4qLmZhY2Vib29rLm5ldIIIKi5mYi5jb22CCyouZmJjZG4u + bmV0ggsqLmZic2J4LmNvbYIQKi5tLmZhY2Vib29rLmNvbYIPKi5tZXNzZW5nZXIu + Y29tgg4qLnh4LmZiY2RuLm5ldIIOKi54eS5mYmNkbi5uZXSCDioueHouZmJjZG4u + bmV0ggxmYWNlYm9vay5jb22CBmZiLmNvbYINbWVzc2VuZ2VyLmNvbTAOBgNVHQ8B + Af8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHUGA1UdHwRu + MGwwNKAyoDCGLmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEyLWhhLXNlcnZl + ci1nNS5jcmwwNKAyoDCGLmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWhh + LXNlcnZlci1nNS5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEF + BQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwgYMG + CCsGAQUFBwEBBHcwdTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu + Y29tME0GCCsGAQUFBzAChkFodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln + aUNlcnRTSEEySGlnaEFzc3VyYW5jZVNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAA + MIICsAYKKwYBBAHWeQIEAgSCAqAEggKcApoAdgCkuQmQtBhYFIe7E6LMZ3AKPDWY + BPkb37jjd80OyA3cEAAAAVjl02IEAAAEAwBHMEUCIQDvWFsUeqWE/xwIYcXPvbb5 + ExzfHBZTNwfnUf4RPO/lBgIgdOGmr0j7+u8/S+7tfFw71ZEjqpwJELl/sEFuQdPn + pwQBLwCsO5rtf6lnR1cVnm19V1Zy+dmBAJQem97/7KExO3V4LQAAAVjl02IoAAAE + AQEAYvnMV+BfP3Wrk4yFQE/Zx5WsjSabYOpLj1Tj5xFaoVoHdGqLCf/Hi+Vv0IRy + ePKFBCSW0+3eA589+WnCDMwcJlBYeZV8MlvHFZg3a66Uhx/OAvoetb0mCtUpnmIE + UwLX/eMNEvjg2qTH3/33ysCo2l25+/EcR8upF+2KIcmnk5WwaJzfq7cFPQc4Cvcz + mTHasJi/jmVaIaJ9HC50g3dx584TQX26lDLddF/Li4uEbJ7TSopnTzjQdWBtWbMF + h3bcfhFCKaqK2kIJV3bgup5HibEnZ2LPm6lekY072ZFCGM4QYc4ukqzou2JWCRmG + o0dMHJhnvQXpnIQGwATqCD4Q1AB2AFYUBpov18Ls0/XhvUSyPsdGdrm8mRFcwO+U + mFXWidDdAAABWOXTYrkAAAQDAEcwRQIgGhXXbwUO5bD4Ts/Q0gqZwUS2vl/A4Hem + k7ovxl82v9oCIQCbtkflDXbcunY4MAQCbKlnesPGc/nftA84xDhJpxFHWQB3AO5L + vbd1zmC64UJpH6vhnmajD35fsHLYgwDEe4l6qP3LAAABWOXTZBEAAAQDAEgwRgIh + AKubngQoa5Iak8eCOrffH7Xx3AP1NMb5pFw35nt2VSeRAiEA47Kq1UQcDXIEsV+W + nuPd9LM5kpdeu0+TiHKtTLRQr0swDQYJKoZIhvcNAQELBQADggEBADrNSsoonbj1 + YGjwy9t9wP9+kZBwrNMO2n5N5fQNhGawkEAX+lXlzgm3TqYlTNi6sCFbPBAErim3 + aMVlWuOlctgnjtAdmdWZ4qEONrBLHPGgukDJ3Uen/EC/gwK6KdBCb4Ttp6MMPY1c + hb/ciTLi3QUUU4h4OJWqUjvccBCDs/LydNjKWZZTxLJmxRSmfpyCU3uU2XHHMNlo + 8UTIlqZsOtdqhg7/Q/cvMDHDkcI/tqelmg0MD2H9KpcmAvVkwgjn+BVpv5HELl+0 + EP0UhYknI1B6LBecJuj7jI26eXZdX35CYkpI/SZA9KK+OYKHh6vCxKqnRZ9ZQUOj + XnIWKQeV5Hg= + -----END CERTIFICATE----- + """ +} + From a578ec1527191846ce6d5a9355362840832bd926 Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 18 Sep 2022 00:02:10 -0700 Subject: [PATCH 43/52] Removed unused code. --- .../LibP2PCryptoTests/LibP2PCryptoTests.swift | 910 +----------------- 1 file changed, 30 insertions(+), 880 deletions(-) diff --git a/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift b/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift index 3e52483..f3d14c5 100644 --- a/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift +++ b/Tests/LibP2PCryptoTests/LibP2PCryptoTests.swift @@ -5,7 +5,6 @@ import Crypto import CryptoSwift import Multihash - /// Secp - https://techdocs.akamai.com/iot-token-access-control/docs/generate-ecdsa-keys /// JWT - https://techdocs.akamai.com/iot-token-access-control/docs/generate-jwt-ecdsa-keys /// Fixtures - http://cryptomanager.com/tv.html @@ -166,6 +165,29 @@ final class libp2p_cryptoTests: XCTestCase { XCTAssertEqual(try keyPair.rawID(), try recoveredPrivateKeyPair.rawID()) } + /// RSA CryptoSwift + func testCryptoSwiftRawRepresentationRoundTrip() throws { + let rsa = try CryptoSwift.RSA(keySize: 1024) + + let extRep = try rsa.externalRepresentation() + print(extRep.toHexString()) + + let pubKeyExtRep = try rsa.publicKeyExternalRepresentation() + print(pubKeyExtRep.toHexString()) + + let recoveredPrivate = try CryptoSwift.RSA(rawRepresentation: rsa.externalRepresentation()) + + XCTAssertEqual(rsa.n, recoveredPrivate.n) + XCTAssertEqual(rsa.e, recoveredPrivate.e) + XCTAssertEqual(rsa.d, recoveredPrivate.d) + + let recoveredPublic = try CryptoSwift.RSA(rawRepresentation: rsa.publicKeyExternalRepresentation()) + + XCTAssertEqual(rsa.n, recoveredPublic.n) + XCTAssertEqual(rsa.e, recoveredPublic.e) + XCTAssertNil(recoveredPublic.d) + } + func testEd25519RawRepresentationRoundTrip() throws { let keyPair = try LibP2PCrypto.Keys.KeyPair(.Ed25519) @@ -285,18 +307,6 @@ final class libp2p_cryptoTests: XCTestCase { XCTAssertEqual(base64MarshaledPublicKey, MarshaledData.PUBLIC_RSA_KEY_1024) } -// func testImportFromMarshalledPublicKey() throws { -// let pubKey = try RawPublicKey(marshaledKey: MarshaledData.PUBLIC_KEY, base: .base64Pad) -// -// /// We've imported a Public Key! 🥳 -// print(pubKey) -// -// /// Now lets try and re-marshal the imported key and make sure it matches the original data... -// let base64MarshaledPublicKey = try pubKey.marshalPublicKey().asString(base: .base64Pad) -// -// XCTAssertEqual(base64MarshaledPublicKey, MarshaledData.PUBLIC_KEY) -// } - func testCreateKeyPairFromMarshalledPublicKey_1024() throws { let keyPair = try LibP2PCrypto.Keys.KeyPair(marshaledPublicKey: MarshaledData.PUBLIC_RSA_KEY_1024, base: .base64Pad) @@ -1122,8 +1132,6 @@ final class libp2p_cryptoTests: XCTestCase { print(asn) } - - func testRSAEncryptedPrivateKeyPem() throws { /* * Generated with @@ -1405,193 +1413,6 @@ final class libp2p_cryptoTests: XCTestCase { //XCTAssertNotEqual(differentPassword, TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.ENCRYPTED) //XCTAssertEqual(differentPassword.count, TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.ENCRYPTED.count) } - - // - MARK: Encrypted PEM Imports - - /// Tests importing encrypted PEM private key with a plaintext password - /// - /// To decrypt an encrypted private RSA key... - /// 1) Strip the headers of the PEM and base64 decode the data - /// 2) Parse the data via ASN1 looking for the encryption algo, salt, iv and itterations used, and the ciphertext (aka octet string) - /// 3) Derive the encryption key using PBKDF2 (sha1, salt and itterations) - /// 4) Use encryption key to instantiate the AES CBC Cipher along with the IV - /// 5) Decrypt the encrypted octet string - /// 6) The decrypted octet string can be ASN1 parsed again for the private key octet string - /// 7) This raw data can be used to instantiate a SecKey -// func testRSAEncryptedPrivateKeyPem2_Manual() throws { -// -// // Generated with -// // openssl genpkey -algorithm RSA -// // -pkeyopt rsa_keygen_bits:1024 -// // -pkeyopt rsa_keygen_pubexp:65537 -// // -out foo.pem -// let unencryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.UNENCRYPTED -// -// // Encrypted with -// // openssl pkcs8 -in foo.pem -topk8 -v2 aes-128-cbc -passout pass:mypassword -// let encryptedPem = TestPEMKeys.RSA_1024_PRIVATE_ENCRYPTED_PAIR.ENCRYPTED -// -// let asn = try Asn1Parser.parse(data: pemToData(encryptedPem)) -// -// print(asn) -// -//// sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //[42,134,72,134,247,13,1,5,13] -//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //PBKDF2 //[42,134,72,134,247,13,1,5,12] -//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.octetString(data: 8 bytes), //SALT -//// libp2p_crypto.Asn1Parser.Node.integer(data: 2 bytes) //ITTERATIONS -//// ]) -//// ]), -//// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -//// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), //des-ede3-cbc [96,134,72,1,101,3,4,1,2] -//// libp2p_crypto.Asn1Parser.Node.octetString(data: 16 bytes) //IV -//// ]) -//// ]) -//// ]), -//// libp2p_crypto.Asn1Parser.Node.octetString(data: 640 bytes) -//// ]) -// -// var saltData:Data? = nil -// var ivData:Data? = nil -// var itterationsData:Int? = nil -// var ciphertextData:Data? = nil -// -// if case .sequence(let top) = asn { -// if case .sequence(let top1) = top.first { -// if case .sequence(let top2) = top1.last { -// if case .sequence(let top3) = top2.first { -// if case .sequence(let top4) = top3.last { -// if case .octetString(let salt) = top4.first { -// print("Found the salt: \(salt.asString(base: .base16))") -// saltData = salt -// } -// if case .integer(let int) = top4.last { -// print("Found the itterations: \(int.asString(base: .base16))") -// itterationsData = Int(int.asString(base: .base16), radix: 16) -// } -// } -// } -// if case .sequence(let bottom3) = top2.last { -// if case .octetString(let iv) = bottom3.last { -// print("Found the IV: \(iv.asString(base: .base16))") -// ivData = iv -// } -// } -// } -// } -// if case .octetString(let cipherText) = top.last { -// print("Found the ciphertext: \(cipherText.count)") -// ciphertextData = cipherText -// } -// } -// -// // Ensure we have everything we need to proceed... -// guard let salt = saltData, let iv = ivData, let itterations = itterationsData, let ciphertext = ciphertextData else { -// return XCTFail("Failed to parse our pcks#8 key") -// } -// -// // Attempt to derive the aes encryption key from the password and salt -// // PBKDF2-SHA1 -// guard let key = PBKDF2.SHA1(password: "mypassword", salt: salt, keyByteCount: 16, rounds: itterations) else { -// return XCTFail("Failed to derive key from password and salt") -// } -// -// // This also works, but it is incredibly slow... -//// let key2 = try PKCS5.PBKDF2( -//// password: Array("mypassword".utf8), -//// salt: salt.bytes, -//// iterations: itterations, -//// keyLength: 16, /* 16 == AES-128, 32 == AES-256 */ -//// variant: .sha256 -//// ).calculate() -// -// // These should be the same -// print("Key 1 -> \(key.asString(base: .base16))") -// //print("Key 2 -> \(key2.asString(base: .base16))") -// -// //Create our CBC AES Cipher -// let aes = try AES(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: .noPadding) -// -// // Try GCM -// //let aes = try AES(key: key.bytes, blockMode: GCM(iv: iv.bytes, mode: .detached), padding: .noPadding) -// -// let decryptedKey = try aes.decrypt(ciphertext.bytes) -// -// print(decryptedKey.asString(base: .base64)) -// -// let deASN = try Asn1Parser.parse(data: Data(decryptedKey)) -// print(deASN) -// print("-----") -// let unASN = try Asn1Parser.parse(data: pemToData(unencryptedPem)) -// print(unASN) -// -// /// sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), // [42,134,72,134,247,13,1,1,1] => RSA Private Key -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 8 bytes), -// /// libp2p_crypto.Asn1Parser.Node.integer(data: 2 bytes) -// /// ]) -// /// ]), -// /// libp2p_crypto.Asn1Parser.Node.sequence(nodes: [ -// /// libp2p_crypto.Asn1Parser.Node.objectIdentifier(data: 9 bytes), -// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 16 bytes) -// /// ]) -// /// ]), -// /// libp2p_crypto.Asn1Parser.Node.octetString(data: 640 bytes) -// /// ]) -// /// ]) -// -// var unencRawPrivateKeyData:Data? = nil -// if case .sequence(let top) = unASN { -// if case .octetString(let d) = top.last { -// print("Found our unenc octetString") -// unencRawPrivateKeyData = d -// } -// } -// -// var decRawPrivateKeyData:Data? = nil -// if case .sequence(let top) = deASN { -// if case .octetString(let d) = top.last { -// print("Found our dec octetString") -// decRawPrivateKeyData = d -// } -// } -// -// guard let uRawPrivKeyData = unencRawPrivateKeyData else { -// return XCTFail("Failed to parse our unencrypted private pem key...") -// } -// -// guard let dRawPrivKeyData = decRawPrivateKeyData else { -// return XCTFail("Failed to parse our decrypted private pem key...") -// } -// -// print(uRawPrivKeyData.asString(base: .base64)) -// print(dRawPrivKeyData.asString(base: .base64)) -// -// print(dRawPrivKeyData.count) -// print(uRawPrivKeyData.count) -// -// let og = try RSAPrivateKey(rawRepresentation: uRawPrivKeyData) -// let de = try RSAPrivateKey(rawRepresentation: dRawPrivKeyData) -// -// print(og) -// -// print(de) -// -// XCTAssertEqual(uRawPrivKeyData, dRawPrivKeyData) -// XCTAssertEqual(og, de) -// -// -// //XCTAssertEqual(uRawPrivKeyData.bytes, decryptedKey, "Not Equal") -// } func testRSAEncryptedPrivateKeyPem2() throws { @@ -1623,90 +1444,6 @@ final class libp2p_cryptoTests: XCTestCase { XCTAssertTrue(attributes!.isPrivate) } - -//// /** -//// * Decrypts the given cipher text with the provided key. The `key` should -//// * be a cryptographically safe key and not a plaintext password. To use -//// * a plaintext password, use `decrypt`. The options used to create -//// * this decryption cipher must be the same as those used to create -//// * the encryption cipher. -//// * -//// * @private -//// * @param {Uint8Array} ciphertextAndNonce The data to decrypt -//// * @param {Uint8Array} key -//// * @returns {Promise} -//// */ -//// async function decryptWithKey (ciphertextAndNonce, key) { // eslint-disable-line require-await -//// // Create Uint8Arrays of nonce, ciphertext and tag. -//// const nonce = ciphertextAndNonce.slice(0, nonceLength) -//// const ciphertext = ciphertextAndNonce.slice(nonceLength, ciphertextAndNonce.length - algorithmTagLength) -//// const tag = ciphertextAndNonce.slice(ciphertext.length + nonceLength) -//// -//// // Create the cipher instance. -//// const cipher = crypto.createDecipheriv(algorithm, key, nonce) -//// -//// // Decrypt and return result. -//// cipher.setAuthTag(tag) -//// return uint8ArrayConcat([cipher.update(ciphertext), cipher.final()]) -//// } -//// -//// /** -//// * Uses the provided password to derive a pbkdf2 key. The key -//// * will then be used to decrypt the data. The options used to create -//// * this decryption cipher must be the same as those used to create -//// * the encryption cipher. -//// * -//// * @param {Uint8Array} data The data to decrypt -//// * @param {string|Uint8Array} password A plain password -//// */ -//// async function decrypt (data, password) { // eslint-disable-line require-await -//// // Create Uint8Arrays of salt and ciphertextAndNonce. -//// const salt = data.slice(0, saltLength) -//// const ciphertextAndNonce = data.slice(saltLength) -//// -//// if (typeof password === 'string' || password instanceof String) { -//// password = uint8ArrayFromString(password) -//// } -//// -//// // Derive the key using PBKDF2. -//// const key = crypto.pbkdf2Sync(password, salt, iterations, keyLength, digest) -//// -//// // Decrypt and return result. -//// return decryptWithKey(ciphertextAndNonce, key) -//// } -//// */ -//// -//// -//// /// Private Key -//// /// Raw Bytes: [1, 187, 116, 255, 157, 152, 71, 218, 87, 128, 62, 200, 148, 52, 164, 109, 237, 133, 89, 216, 240, 207, 80, 244, 60, 41, 32, 117, 184, 2, 231, 7, 9, 237, 110, 180, 86, 120, 103, 133, 84, 215, 104, 137, 101, 171, 127, 154, 54, 153, 229, 201, 46, 20, 1, 221, 211, 59, 129, 102, 129, 5, 76, 249, 30, 182] -//// /// Bytes: 66 -//// /// --- -//// /// Public Key -//// /// Raw Bytes: [0, 110, 196, 197, 185, 248, 73, 76, 67, 3, 127, 38, 67, 168, 163, 6, 20, 223, 146, 233, 198, 22, 77, 105, 120, 172, 14, 6, 95, 144, 206, 161, 48, 16, 46, 29, 26, 53, 177, 60, 132, 212, 146, 37, 203, 104, 104, 81, 129, 246, 149, 222, 98, 0, 249, 7, 134, 50, 83, 122, 75, 74, 242, 216, 234, 152, 0, 196, 255, 251, 57, 249, 20, 79, 95, 72, 156, 153, 174, 189, 153, 145, 253, 72, 69, 57, 114, 180, 179, 100, 173, 183, 100, 235, 84, 42, 66, 116, 93, 139, 64, 190, 225, 15, 90, 159, 178, 212, 204, 25, 174, 159, 36, 177, 45, 227, 230, 147, 191, 167, 141, 103, 47, 96, 183, 159, 143, 89, 155, 144, 199, 38] -//// /// Bytes: 132 -//// /// --- -//// func testECRawRep() throws { -//// let key = P521.Signing.PrivateKey() -//// -//// let rawPrivKey = key.rawRepresentation -//// let rawPubKey = key.publicKey.rawRepresentation -//// -//// //print(key.x963Representation.asString(base: .base64)) -//// print("Private Key") -//// print("Raw Bytes: \(rawPrivKey.bytes)") -//// print("Bytes: \(rawPrivKey.bytes.count)") -//// print("---") -//// //print(rawRep.asString(base: .base64)) -//// print("Public Key") -//// print("Raw Bytes: \(rawPubKey.bytes)") -//// print("Bytes: \(rawPubKey.bytes.count)") -//// print("---") -//// -//// let importedKey = try P521.Signing.PrivateKey(rawRepresentation: rawPrivKey) -//// -//// print(importedKey) -//// } - func testRSA_Pem_Parsing_Public() throws { //let parsed = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.RSA_1024_PUBLIC) let rsaPublic = try RSAPublicKey(pem: TestPEMKeys.RSA_1024_PUBLIC, asType: RSAPublicKey.self) @@ -1754,112 +1491,6 @@ final class libp2p_cryptoTests: XCTestCase { print(parsed) } - /// openssl ecparam -genkey -name secp256k1 -out ec_key.pem -param_enc explicit - /// Create Secp256k1 Key: `openssl ecparam -name secp256k1 -genkey -noout -out ec-secp256k1-priv-key.pem` - /// Create Public PEM from Private PEM: `openssl ec -in ec-secp256k1-priv-key.pem -pubout > ec-secp256k1-pub-key.pem` -// func testSecp256k1_Pem_Parsing_Public() throws { -// //let parsed = try LibP2PCrypto.Keys.parsePem(TestPEMKeys.SECP256k1_KeyPair.PUBLIC) -// -// //print(parsed) -// -// //2a8648ce3d0201 -// //2b8104000a -// //let secp256k1Public = try Secp256k1PublicKey(pem: TestPEMKeys.SECP256k1_KeyPair.PUBLIC, asType: Secp256k1PublicKey.self) -// -// //print(secp256k1Public) -// -// //let secp256k1Private = try Secp256k1PrivateKey(pem: TestPEMKeys.SECP256k1_KeyPair.PRIVATE, asType: Secp256k1PrivateKey.self) -// -// //print(secp256k1Private) -// -//// XCTAssertEqual(secp256k1Private.publicKey, secp256k1Public) -// -// /// 0:d=0 hl=3 l= 162 cons: SEQUENCE -// /// 3:d=1 hl=2 l= 1 prim: INTEGER :01 -// /// 6:d=1 hl=2 l= 44 cons: SEQUENCE -// /// 8:d=2 hl=2 l= 7 prim: OBJECT :prime-field -// /// 17:d=2 hl=2 l= 33 prim: INTEGER :FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F -// /// 52:d=1 hl=2 l= 6 cons: SEQUENCE -// /// 54:d=2 hl=2 l= 1 prim: OCTET STRING [HEX DUMP]:00 -// /// 57:d=2 hl=2 l= 1 prim: OCTET STRING [HEX DUMP]:07 -// /// 60:d=1 hl=2 l= 65 prim: OCTET STRING [HEX DUMP]:0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8 -// /// 127:d=1 hl=2 l= 33 prim: INTEGER :FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 -// /// 162:d=1 hl=2 l= 1 prim: INTEGER :01 -// let ecPEM = """ -// -----BEGIN EC PRIVATE KEY----- -// MIIBEwIBAQQgiOURdsStmumMgM2c29TlUxEdNxrQns8VPeM0sV08MtKggaUwgaIC -// AQEwLAYHKoZIzj0BAQIhAP////////////////////////////////////7///wv -// MAYEAQAEAQcEQQR5vmZ++dy7rFWgYpXOhwsHApv82y3OKNlZ8oFbFvgXmEg62ncm -// o8RlXaT7/A4RCKj9F7RIpoVUGZxH0I/7ENS4AiEA/////////////////////rqu -// 3OavSKA7v9JejNA2QUECAQGhRANCAASDsnwEULWLn8HV8iobNGNAdze/SbwbehJ3 -// l+gvkHpYQ2tMD9d4NTMDKFTxPUN+w0ktADgGaPhd2flQ2dNL7nFT -// -----END EC PRIVATE KEY----- -// """ -// let ecPEM2 = """ -// -----BEGIN EC PRIVATE KEY----- -// MHQCAQEEIFTQEjBp0zAIiafoD6+xwBS/kAvc4qq0BVZ1QTk//EguoAcGBSuBBAAK -// oUQDQgAEmLNqAvsnenwfMz8+U5MUGb4zwhfxVBjRqn7Bqa/CCVPtsqSMfhzaE30u -// OQlpl7VjL/jrZYpUv8aPRfTBSn396w== -// -----END EC PRIVATE KEY----- -// """ -// -// let ecParams = """ -// -----BEGIN EC PARAMETERS----- -// BgUrgQQACg== -// -----END EC PARAMETERS----- -// """ -// -// let ecPEMPrivate = """ -// -----BEGIN EC PRIVATE KEY----- -// MHQCAQEEINMfarC/mmrd3GKaOfl+7iXffsdg4MqMa4HY5wkBDilooAcGBSuBBAAK -// oUQDQgAEJ9kHLQX2sVEh14Duq23w5af30636vUx93jVsMIDhONwwuQc2N7mv4/oY -// 8oB3EPTRyh+o+6J+9qXI1VaJjvSr5Q== -// -----END EC PRIVATE KEY----- -// """ -// let ecPEMPublic = """ -// -----BEGIN PUBLIC KEY----- -// MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEJ9kHLQX2sVEh14Duq23w5af30636vUx9 -// 3jVsMIDhONwwuQc2N7mv4/oY8oB3EPTRyh+o+6J+9qXI1VaJjvSr5Q== -// -----END PUBLIC KEY----- -// """ -// -// let pemBase64String = ecPEM2.split(separator: "\n").dropFirst().dropLast().joined() -// let pemData = Data(base64Encoded: pemBase64String)! -// -// print(pemData.toHexString()) -// -// //30820113 -// // 020101 -// // 042088e51176c4ad9ae98c80cd9cdbd4e553111d371ad09ecf153de334b15d3c32d2a081a53081a2 -// // 020101 -// // 302c06072a8648ce3d0101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f -// // 3006 -// // 040100 -// // 040107 -// // 04410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 -// // 022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0//364141 -// // 020101 -// // a144 -// // 0342 -// // 00 -// // 0483b27c0450b58b9fc1d5f22a1b3463407737bf49bc1b7a127797e82f907a58436b4c0fd7783533032854f13d437ec3492d00380668f85dd9f950d9d34bee7153 -// -// -// //3074 -// // 020101 -// // 042054d0123069d3300889a7e80fafb1c014bf900bdce2aab405567541393ffc -// //482ea00706052b8104000aa1440342000498b36a02fb277a7c1f333f3e53931419be33c217f15418d1aa7ec1a9afc20953edb2a48c7e1cda137d2e39096997b5632ff8eb658a54bfc68f45f4c14a7dfdeb -// -// let parsed = try ASN1.Decoder.decode(data: pemData) -// -// print(parsed) -// -//// if case .octetString(let rawData) = parsed { -//// let edPrivate = try Curve25519.Signing.PrivateKey(rawRepresentation: rawData) -//// print(edPrivate) -//// } -// } - func testSecp256k1_Pem_Parsing_Private() throws { let parsed = try LibP2PCrypto.Keys.KeyPair(pem: TestPEMKeys.SECP256k1_KeyPair.PRIVATE) @@ -1878,121 +1509,7 @@ final class libp2p_cryptoTests: XCTestCase { XCTAssertEqual(secp256k1Private.publicKey, secp256k1Public) } - /// -----BEGIN PGP PUBLIC KEY BLOCK----- - /// Comment: C459 E542 8084 7C93 79BE 9AED DA30 E629 61F6 0A75 - /// Comment: Alice Wonderland - /// - /// xsDNBGH7EL8BDADovR5cjh9P26RJ2uNxHuaEmdSFTY6q2uE5s4C6G+JEmtyuqhC9 - /// HEHgl7hv9LbsskLs50J0cCH9KQzMSl2OxztVGR8ABV06oDB+7fhHEPXNA4m1cLmQ - /// zGCp9uDxCs3tuDJRkEMSo97T6AnQwDsl5rBBMqR9c/B7Ozml1aER6ehtxSQt7tuu - /// x/9oD+9zFyUsBOuO20d/Km629h6IHfF+BadbJpzAqHunq+w2P4ks7XYlhFJdhMIq - /// W0h31rI1CO4tM+DG7+6Osz6EJeHWZOc9tWM/5YxmJOA7SZU4t+yedif4bzC4+aCH - /// W2AYlrWKivNOe4n46u1J+xlCtnLyK9Si39ylDuem118diaW1Qs99PkTbWawagYyc - /// c+0flTYeWugLxc2LDUfq9b6r7tfu9hyez0TghdRwlvrQlnZCmEt/Ndg0YF0N3BFE - /// dAzdpsiddEytH28L7hwHE5lECam4mGxBe8uNGYlDu8Viq7IYhyfCM0CNGlEwUQIW - /// I7ahSbKTX66aZxcAEQEAAc0lTG93ZWxsIFRvbXMgPGxvd2VsbHMudmF1bHRAZ21h - /// aWwuY29tPsLBFAQTAQoAPhYhBMRZ5UKAhHyTeb6a7dow5ilh9gp1BQJh+xC/AhsD - /// BQkDwmcABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJENow5ilh9gp1sNoMAItC - /// peoNv5MLrf5XJzP+bi+qmyAkiQSQ+0Jd17G1bUgrmpjeWXUqxu3fWgdxC6+CQLM9 - /// Fj69v11G1nrNlII0vyUN0nxPf9LS5qPMQKXZeAvT+lYrPaNWoE4ShI7MnJhxbME9 - /// TlQNikjOYgWt5dNlO+XqWAqP9ECQ0D2x2ulypVvhYPpvslp0+dQJGfIteTzqHHIY - /// Cu7drWh5Sjy2pvIKOIjjrKapjwqidy6laDi4NDhbu/JWp4im1ZRpIU6qTZgH4b+U - /// kCiAScNbnkYWtlIJ73j+Mh62FzZFQ+lSlVI8Fe/POyCwphVUw9smaEMO1WCsg0zP - /// LLAfnVLhWXdaB1QfchlWU1C/zVtnyCZvkVzDTFCa4IyBrAqUCnXfJHOgivtUU4rl - /// FvgynrDmeKjUqxJsVpEDS524nxR7aVdnfj34879SlJdliHeuwgpYF1q3eQYJMrR/ - /// wDCRBxbGpHTCOVjtU6GEeE9mV93SwVFAFHokD/iJMNTmGiUxFubHQXqCuAKuCc7A - /// zQRh+xC/AQwA0NZs9RjrGAicIFIp6C7NHheyFDL8tet5ZDPO2Lya22AXgnWo3/bs - /// QGXOlxhHJB7TK3Ma5wHAUKJ4BEvxpMtSwHnkFf/EAFZug2AXIvhJpdT8j/Lct6er - /// VusrPxfDmlTH0QeKl3IklnvowyO3r6VeI2Lxga0gWlV+/gRq0vzwXM4vqeXzjNFo - /// cCuNq4jSFT+zztYkud8GbAULBB5oeAp1Dhp+Uk84tu2Lg8rbBhK/H/ax4ozUrWi2 - /// G6azGx9psW9yq+LnQXaCSeGTn8XMqXzuwiD87TZgvuih/8iyMDoaFnuSKCw4v1WQ - /// 8wWusZ2e0a05SCiRpYDlv+CJ93J5F1ApZXjD9NpYcU0O53zl+wqqNbj1HtxoGPrT - /// EHvKPYZru/Dtea+sAxEXpYpUXFamQq4zIaI+dagD3vzSmFLRuCtaZElHhsS3t91K - /// tQBKon1ZEN/VwdO7tix6gfDMMa3BpnllI2eaw2X+Ucdkm/jJHuPoxfy1lbFP8byy - /// fDXvhR8Pnk8TABEBAAHCwPwEGAEKACYWIQTEWeVCgIR8k3m+mu3aMOYpYfYKdQUC - /// YfsQvwIbDAUJA8JnAAAKCRDaMOYpYfYKddh5DADGLKm9AmtCh7bUR+r+MKdCyjTO - /// LSiu0WACRUHIw+RLu5J5/haa7xZKPo6iN955oUS3j9CK0NTr/+ZxdDFwVc7kAjOn - /// eoZefac0CFRtLO26LQcVh5jc6YV0ZVtchvbnWCOfwtsvVfsQUCo7oIfP2CacEGq2 - /// EIqYLTJ7leVgo3AqlR5MmPA+umMKVcb/KDkesMnhgThw3F+81cocRhxWVlNQam0/ - /// PAj2uprXt+yWU8K94gojmolBuSdBBMZGArjBr/oCAhBrWarg4gEnC0tGQBBLU1Us - /// YEdv+2OYokrlIU96P2mtCDX+9GId+idUlgEPc+CQr3Um9W/syyxGI2e2wSlAlkjh - /// +h84GvLvZpM9HU4HrHF5AxmXoEe2BF7ICHHju0vdignpEdtQ/XHckSLlxcJz8i2S - /// XkMi7m1i5U0OWEXVr+Z3jeW2HVVEvEJ7aXL3oLLAVz3TROFY0M41zjrstyjg0sg5 - /// 5H93wgN5hgZ8MeDFEWbEh3p7e/MP9I/lo70bkA0= - /// =n56n - /// -----END PGP PUBLIC KEY BLOCK----- -// func testOpen_ASC_PGP_PublicKey() throws { -// let urls = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask) -// let downloadsFolder = urls[0] -// -// print(downloadsFolder) -// let fileURL = downloadsFolder.appendingPathComponent("C459E54280847C9379BE9AEDDA30E62961F60A75.asc") -// -// let pubKey = try String(contentsOf: fileURL, encoding: .utf8) -// -// print(pubKey) -// -// //let keyPair = try LibP2PCrypto.Keys.parsePem(pubKey) -// let keyPair = try LibP2PCrypto.Keys.importPublicPem(pubKey) -// -// print(keyPair) -// } - -// func testOpen_PGP_PublicKey() throws { -// -// let pubKey = """ -// xsDNBGH7EL8BDADovR5cjh9P26RJ2uNxHuaEmdSFTY6q2uE5s4C6G+JEmtyuqhC9 -// HEHgl7hv9LbsskLs50J0cCH9KQzMSl2OxztVGR8ABV06oDB+7fhHEPXNA4m1cLmQ -// zGCp9uDxCs3tuDJRkEMSo97T6AnQwDsl5rBBMqR9c/B7Ozml1aER6ehtxSQt7tuu -// x/9oD+9zFyUsBOuO20d/Km629h6IHfF+BadbJpzAqHunq+w2P4ks7XYlhFJdhMIq -// W0h31rI1CO4tM+DG7+6Osz6EJeHWZOc9tWM/5YxmJOA7SZU4t+yedif4bzC4+aCH -// W2AYlrWKivNOe4n46u1J+xlCtnLyK9Si39ylDuem118diaW1Qs99PkTbWawagYyc -// c+0flTYeWugLxc2LDUfq9b6r7tfu9hyez0TghdRwlvrQlnZCmEt/Ndg0YF0N3BFE -// dAzdpsiddEytH28L7hwHE5lECam4mGxBe8uNGYlDu8Viq7IYhyfCM0CNGlEwUQIW -// I7ahSbKTX66aZxcAEQEAAc0lTG93ZWxsIFRvbXMgPGxvd2VsbHMudmF1bHRAZ21h -// aWwuY29tPsLBFAQTAQoAPhYhBMRZ5UKAhHyTeb6a7dow5ilh9gp1BQJh+xC/AhsD -// BQkDwmcABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJENow5ilh9gp1sNoMAItC -// peoNv5MLrf5XJzP+bi+qmyAkiQSQ+0Jd17G1bUgrmpjeWXUqxu3fWgdxC6+CQLM9 -// Fj69v11G1nrNlII0vyUN0nxPf9LS5qPMQKXZeAvT+lYrPaNWoE4ShI7MnJhxbME9 -// TlQNikjOYgWt5dNlO+XqWAqP9ECQ0D2x2ulypVvhYPpvslp0+dQJGfIteTzqHHIY -// Cu7drWh5Sjy2pvIKOIjjrKapjwqidy6laDi4NDhbu/JWp4im1ZRpIU6qTZgH4b+U -// kCiAScNbnkYWtlIJ73j+Mh62FzZFQ+lSlVI8Fe/POyCwphVUw9smaEMO1WCsg0zP -// LLAfnVLhWXdaB1QfchlWU1C/zVtnyCZvkVzDTFCa4IyBrAqUCnXfJHOgivtUU4rl -// FvgynrDmeKjUqxJsVpEDS524nxR7aVdnfj34879SlJdliHeuwgpYF1q3eQYJMrR/ -// wDCRBxbGpHTCOVjtU6GEeE9mV93SwVFAFHokD/iJMNTmGiUxFubHQXqCuAKuCc7A -// zQRh+xC/AQwA0NZs9RjrGAicIFIp6C7NHheyFDL8tet5ZDPO2Lya22AXgnWo3/bs -// QGXOlxhHJB7TK3Ma5wHAUKJ4BEvxpMtSwHnkFf/EAFZug2AXIvhJpdT8j/Lct6er -// VusrPxfDmlTH0QeKl3IklnvowyO3r6VeI2Lxga0gWlV+/gRq0vzwXM4vqeXzjNFo -// cCuNq4jSFT+zztYkud8GbAULBB5oeAp1Dhp+Uk84tu2Lg8rbBhK/H/ax4ozUrWi2 -// G6azGx9psW9yq+LnQXaCSeGTn8XMqXzuwiD87TZgvuih/8iyMDoaFnuSKCw4v1WQ -// 8wWusZ2e0a05SCiRpYDlv+CJ93J5F1ApZXjD9NpYcU0O53zl+wqqNbj1HtxoGPrT -// EHvKPYZru/Dtea+sAxEXpYpUXFamQq4zIaI+dagD3vzSmFLRuCtaZElHhsS3t91K -// tQBKon1ZEN/VwdO7tix6gfDMMa3BpnllI2eaw2X+Ucdkm/jJHuPoxfy1lbFP8byy -// fDXvhR8Pnk8TABEBAAHCwPwEGAEKACYWIQTEWeVCgIR8k3m+mu3aMOYpYfYKdQUC -// YfsQvwIbDAUJA8JnAAAKCRDaMOYpYfYKddh5DADGLKm9AmtCh7bUR+r+MKdCyjTO -// LSiu0WACRUHIw+RLu5J5/haa7xZKPo6iN955oUS3j9CK0NTr/+ZxdDFwVc7kAjOn -// eoZefac0CFRtLO26LQcVh5jc6YV0ZVtchvbnWCOfwtsvVfsQUCo7oIfP2CacEGq2 -// EIqYLTJ7leVgo3AqlR5MmPA+umMKVcb/KDkesMnhgThw3F+81cocRhxWVlNQam0/ -// PAj2uprXt+yWU8K94gojmolBuSdBBMZGArjBr/oCAhBrWarg4gEnC0tGQBBLU1Us -// YEdv+2OYokrlIU96P2mtCDX+9GId+idUlgEPc+CQr3Um9W/syyxGI2e2wSlAlkjh -// +h84GvLvZpM9HU4HrHF5AxmXoEe2BF7ICHHju0vdignpEdtQ/XHckSLlxcJz8i2S -// XkMi7m1i5U0OWEXVr+Z3jeW2HVVEvEJ7aXL3oLLAVz3TROFY0M41zjrstyjg0sg5 -// 5H93wgN5hgZ8MeDFEWbEh3p7e/MP9I/lo70bkA0= -// =n56n -// """ -// -// let data = try BaseEncoding.decode(pubKey, as: .base64) -// print(data) -// -// //let keyPair = try LibP2PCrypto.Keys.parsePem(pubKey) -// //let keyPair = try LibP2PCrypto.Keys.importPublicPem(pubKey) -// //let keyPair = try LibP2PCrypto.Keys.importPublicDER(pubKey) -// //let keyPair = try LibP2PCrypto.Keys. -// -// //print(keyPair) -// } - - /// Is the public key embedded in these IDs?? + /// The public key is embedded in certain PeerID's /// Dialed: 12D3KooWAfPDpPRRRBrmqy9is2zjU5srQ4hKuZitiGmh4NTTpS2d /// Provided: QmPoHmYtUt8BU9eiwMYdBfT6rooBnna5fdAZHUaZASGQY8 /// QmPoHmYtUt8BU9eiwMYdBfT6rooBnna5fdAZHUaZASGQY8 @@ -2001,21 +1518,23 @@ final class libp2p_cryptoTests: XCTestCase { /// Provided: Qmbp3SxL2SYcH6Ly4r5SGQwfxkDCJPuhJG35GCZimcTiBc /// Qmbp3SxL2SYcH6Ly4r5SGQwfxkDCJPuhJG35GCZimcTiBc func testEmbeddedEd25519PublicKey() throws { - let multi = try Multihash(b58String: "12D3KooWF5Qbrbvhhha1AcqRULWAfYzFEnKvWVGBUjw489hpo5La") print(multi) print("\(multi.value) (\(multi.value.count))") print("\(multi.digest!) (\(multi.digest!.count))") + /// Ensure we can instantiate a ED25519 Public Key from the multihash's digest (identity) let key = try Curve25519.Signing.PublicKey(rawRepresentation: multi.digest!.dropFirst(4)) print(key) + /// Ensure we can instantiate a KeyPair with the public key let kp = try LibP2PCrypto.Keys.KeyPair(publicKey: key) - print(kp) + XCTAssertEqual(kp.keyType, .ed25519) print(try kp.id(withMultibasePrefix: false)) + /// Ensure we can instantiate a key pair directly from the Multihash's Digest (Identity) let marshed = try LibP2PCrypto.Keys.KeyPair(marshaledPublicKey: Data(multi.digest!)) print(marshed) @@ -2023,6 +1542,7 @@ final class libp2p_cryptoTests: XCTestCase { print(marshed.publicKey) print(try marshed.id(withMultibasePrefix: false)) + XCTAssertEqual(try marshed.id(withMultibasePrefix: false), "12D3KooWF5Qbrbvhhha1AcqRULWAfYzFEnKvWVGBUjw489hpo5La") } static var allTests = [ @@ -2032,6 +1552,7 @@ final class libp2p_cryptoTests: XCTestCase { ("testRSARawRepresentationRoundTrip", testRSARawRepresentationRoundTrip), ("testEd25519RawRepresentationRoundTrip", testEd25519RawRepresentationRoundTrip), ("testSecP256k1RawRepresentationRoundTrip", testSecP256k1RawRepresentationRoundTrip), + ("testCryptoSwiftRawRepresentationRoundTrip", testCryptoSwiftRawRepresentationRoundTrip), ("testRSAMarshaledRoundTrip", testRSAMarshaledRoundTrip), ("testRSAMashallingRoundTrip", testRSAMashallingRoundTrip), ("testED25519MarshallingRoundTrip", testED25519MarshallingRoundTrip), @@ -2089,374 +1610,3 @@ final class libp2p_cryptoTests: XCTestCase { ("testEmbeddedEd25519PublicKey", testEmbeddedEd25519PublicKey) ] } - - -// /// Eliptic Curves -// func testEC256() throws { -// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.EC(curve: .P256)) -// print(keyPair) -// } -// -// func testEC256KeyPair() throws { -// let keyPair = try LibP2PCrypto.Keys.generateKeyPair(.EC(curve: .P256)) -// XCTAssertFalse(keyPair.publicKey.isRSAKey) -// XCTAssertTrue(keyPair.publicKey.isPublicKey) -// XCTAssertFalse(keyPair.privateKey.isPublicKey) -// } -// -// func testECDSA256() throws { -// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.ECDSA(curve: .P256)) -// print(keyPair) -// } -// -// func testECDSA384() throws { -// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.ECDSA(curve: .P384)) -// print(keyPair) -// } -// -// func testECDSA521() throws { -// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.ECDSA(curve: .P521)) -// print(keyPair) -// } -// -// func testECSecPrimeRandom() throws { -// let keyPair = try LibP2PCrypto.Keys.generateRawKeyPair(.ECSECPrimeRandom()) -// print(keyPair) -// } - -// func testEphemeralMashallingRoundTrip() throws { -// let keyPair = try LibP2PCrypto.Keys.generateRawEphemeralKeyPair(curve: .P256) -// -// print("Public Key: \(keyPair.publicKey.asString(base: .base16))") -// -// let marshaledPubKey = try LibP2PCrypto.Keys.marshalPublicKey(raw: keyPair.publicKey, keyType: .ECDSA(curve: .P256)) -// print("Marshaled PubKey Bytes: \(marshaledPubKey)") -// -// let unmarshaledPubKey = try LibP2PCrypto.Keys.unmarshalPublicKey(buf: marshaledPubKey, into: .base16) -// -// print("Public Key: \(unmarshaledPubKey)") -// XCTAssertEqual(unmarshaledPubKey, keyPair.publicKey.asString(base: .base16)) -// } -// - -// func testPemParsing_EC_256_Private_Key() throws { -// let pem = """ -// -----BEGIN EC PRIVATE KEY----- -// MHcCAQEEIHwS3r7tdBfDPSOaT/x6A2qvXFFXlGmnaYkxzrj1CQUHoAoGCCqGSM49 -// AwEHoUQDQgAE79HvsMQC9IyhZ7yCCYKmgz9zewM4KziWoVMXKN+7Cd5Ds+jK8V5q -// hD6YVbbo/v1udmM5DfhHJiUW3Ww5++suRg== -// -----END EC PRIVATE KEY----- -// """ -// -// let chunks = pem.split(separator: "\n") -// guard chunks.count > 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } -// -// let raw = try BaseEncoding.decode(chunks[1.. 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } -// -// let raw = try BaseEncoding.decode(chunks[1.. 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } -// -// let raw = try BaseEncoding.decode(chunks[1.. 2a 86 48 86 f7 0d 01 01 01 (bit length independent, pub/priv key independent) -/// ECDSA P384 --> 2a 86 48 ce 3d 02 01 -// func testPemParsing() throws { -// -//// let pem = """ -//// -----BEGIN PUBLIC KEY----- -//// MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcZ/r0nvJyHUUstIB5BqCUJ1CC -//// Cd1nzle4bEpPQJ/S0Wn7mV2FDAeh+UcbVhZu9n+5zypYNjeZKapPqBLoT8eCK51y -//// Kpzeb8LuEm3P8PK4xN18XBrIF1GprN8IIgSdK9f5SwnemutcURrY+PlWnvj7N5s/ -//// 03RlJA3/NHVXpPW/VQIDAQAB -//// -----END PUBLIC KEY----- -//// """ -// -// let pem = """ -// -----BEGIN PRIVATE KEY----- -// MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQDp0Whyqa8KmdvK -// 0MsQGJEBzDAEHAZc0C6cr0rkb6Xwo+yB5kjZBRDORk0UXtYGE1pYt4JhUTmMzcWO -// v2xTIsdbVMQlNtput2U8kIqS1cSTkX5HxOJtCiIzntMzuR/bGPSOexkyFQ8nCUqb -// ROS7cln/ixprra2KMAKldCApN3ue2jo/JI1gyoS8sekhOASAa0ufMPpC+f70sc75 -// Y53VLnGBNM43iM/2lsK+GI2a13d6rRy86CEM/ygnh/EDlyNDxo+SQmy6GmSv/lmR -// xgWQE2dIfK504KIxFTOphPAQAr9AsmcNnCQLhbz7YTsBz8WcytHGQ0Z5pnBQJ9AV -// CX9E6DFHetvs0CNLVw1iEO06QStzHulmNEI/3P8I1TIxViuESJxSu3pSNwG1bSJZ -// +Qee24vvlz/slBzK5gZWHvdm46v7vl5z7SA+whncEtjrswd8vkJk9fI/YTUbgOC0 -// HWMdc2t/LTZDZ+LUSZ/b2n5trvdJSsOKTjEfuf0wICC08pUUk8MCAwEAAQKCAYEA -// ywve+DQCneIezHGk5cVvp2/6ApeTruXalJZlIxsRr3eq2uNwP4X2oirKpPX2RjBo -// NMKnpnsyzuOiu+Pf3hJFrTpfWzHXXm5Eq+OZcwnQO5YNY6XGO4qhSNKT9ka9Mzbo -// qRKdPrCrB+s5rryVJXKYVSInP3sDSQ2IPsYpZ6GW6Mv56PuFCpjTzElzejV7M0n5 -// 0bRmn+MZVMVUR54KYiaCywFgUzmr3yfs1cfcsKqMRywt2J58lRy/chTLZ6LILQMv -// 4V01neVJiRkTmUfIWvc1ENIFM9QJlky9AvA5ASvwTTRz8yOnxoOXE/y4OVyOePjT -// cz9eumu9N5dPuUIMmsYlXmRNaeGZPD9bIgKY5zOlfhlfZSuOLNH6EHBNr6JAgfwL -// pdP43sbg2SSNKpBZ0iSMvpyTpbigbe3OyhnFH/TyhcC2Wdf62S9/FRsvjlRPbakW -// YhKAA2kmJoydcUDO5ccEga8b7NxCdhRiczbiU2cj70pMIuOhDlGAznyxsYbtyxaB -// AoHBAPy6Cbt6y1AmuId/HYfvms6i8B+/frD1CKyn+sUDkPf81xSHV7RcNrJi1S1c -// V55I0y96HulsR+GmcAW1DF3qivWkdsd/b4mVkizd/zJm3/Dm8p8QOnNTtdWvYoEB -// VzfAhBGaR/xflSLxZh2WE8ZHQ3IcRCXV9ZFgJ7PMeTprBJXzl0lTptvrHyo9QK1v -// obLrL/KuXWS0ql1uSnJr1vtDI5uW8WU4GDENeU5b/CJHpKpjVxlGg+7pmLknxlBl -// oBnZnQKBwQDs2Ky29qZ69qnPWowKceMJ53Z6uoUeSffRZ7xuBjowpkylasEROjuL -// nyAihIYB7fd7R74CnRVYLI+O2qXfNKJ8HN+TgcWv8LudkRcnZDSvoyPEJAPyZGfr -// olRCXD3caqtarlZO7vXSAl09C6HcL2KZ8FuPIEsuO0Aw25nESMg9eVMaIC6s2eSU -// NUt6xfZw1JC0c+f0LrGuFSjxT2Dr5WKND9ageI6afuauMuosjrrOMl2g0dMcSnVz -// KrtYa7Wi1N8CgcBFnuJreUplDCWtfgEen40f+5b2yAQYr4fyOFxGxdK73jVJ/HbW -// wsh2n+9mDZg9jIZQ/+1gFGpA6V7W06dSf/hD70ihcKPDXSbloUpaEikC7jxMQWY4 -// uwjOkwAp1bq3Kxu21a+bAKHO/H1LDTrpVlxoJQ1I9wYtRDXrvBpxU2XyASbeFmNT -// FhSByFn27Ve4OD3/NrWXtoVwM5/ioX6ZvUcj55McdTWE3ddbFNACiYX9QlyOI/TY -// bhWafDCPmU9fj6kCgcEAjyQEfi9jPj2FM0RODqH1zS6OdG31tfCOTYicYQJyeKSI -// /hAezwKaqi9phHMDancfcupQ89Nr6vZDbNrIFLYC3W+1z7hGeabMPNZLYAs3rE60 -// dv4tRHlaNRbORazp1iTBmvRyRRI2js3O++3jzOb2eILDUyT5St+UU/LkY7R5EG4a -// w1df3idx9gCftXufDWHqcqT6MqFl0QgIzo5izS68+PPxitpRlR3M3Mr4rCU20Rev -// blphdF+rzAavYyj1hYuRAoHBANmxwbq+QqsJ19SmeGMvfhXj+T7fNZQFh2F0xwb2 -// rMlf4Ejsnx97KpCLUkoydqAs2q0Ws9Nkx2VEVx5KfUD7fWhgbpdnEPnQkfeXv9sD -// vZTuAoqInN1+vj1TME6EKR/6D4OtQygSNpecv23EuqEvyXWqRVsRt9Qd2B0H4k7h -// gnjREs10u7zyqBIZH7KYVgyh27WxLr859ap8cKAH6Fb+UOPtZo3sUeeume60aebn -// 4pMwXeXP+LO8NIfRXV8mgrm86g== -// -----END PRIVATE KEY----- -// """ -// -//// /// EC P256 Public Key -//// let pem = """ -//// -----BEGIN PUBLIC KEY----- -//// MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEb4nB0k8CBVnKCHVHkxuXAkSlZuO5 -//// Nsev1rzcRv5QHiJuWUKomFGadQlMSGwoDOHEDdW3ujcA6t0ADteHw6KrZg== -//// -----END PUBLIC KEY----- -//// """ -// -//// /// EC P384 Public Key -//// let pem = """ -//// -----BEGIN PUBLIC KEY----- -//// MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEBwY0l7mq7hSBEZRld5ISWfSoFsYN3wwM -//// hdD3cMU95DmYXzbqVHB4dCfsy7bexm4h9c0zs4CyTPzy3DV3vfmv1akQJIQv7l08 -//// lx/YXNeGXTN4Gr9r4rwA5GvRl1p6plPL -//// -----END PUBLIC KEY----- -//// """ -// -//// /// EC P521 Public Key -//// let pem = """ -//// -----BEGIN PUBLIC KEY----- -//// MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAp3v1UQWvSyQnkAUEBu+x/7ZrPtNJ -//// SCUk9kMvuZMyGP1idwvspALuJjzrSFFlXObjlOjxucSbWhTYF/o3nc0XzpAA3dxA -//// BYiMqH9vrVePoJMpv+DMdkUiUJ/WqHSOu9bJEi1h4fdqh5HHx4QZJY/iX/59VAi1 -//// uSbAhALvbdGFbVpkcOs= -//// -----END PUBLIC KEY----- -//// """ -// -// /// EC P256 Private Key -//// let pem = """ -//// -----BEGIN PRIVATE KEY----- -//// MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgZjQLlzempZx7YF1F -//// +MK1HWZTNgLcC1MAufb/2/YZYk6hRANCAAQwgn0PfkIHiZ/K+3zA//CoDqU2PqDc -//// aA3U5R68jmlZQITvMyBlMJl9Mjh0biIe88dAfRKeUm9FVMD2ErJ/006V -//// -----END PRIVATE KEY----- -//// """ -// -// /// PEMP384PKCS8 -//// let pem = """ -//// -----BEGIN PRIVATE KEY----- -//// MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDB7ERKhMR+mvz1NQ+oL -//// i6ZJMACOcwbUetWcNnB4Mnx3j4XuhpkkHEW8E1+rXyjZ3UmhZANiAASYH+emlyXM -//// kBSFJl0BiopDVuIIR47M4pLl00YNnuu/Rp5VHeVAHrP67i2Q92u5fk34eOSwQvkO -//// VvktWsgtzAomIam4SHqE9bhvrHy6kW6QzxlERHTL+YkXEX8c6t8VOxk= -//// -----END PRIVATE KEY----- -//// """ -// -// let chunks = pem.split(separator: "\n") -// guard chunks.count > 3, -// let f = chunks.first, f.hasPrefix("-----BEGIN"), -// let l = chunks.last, l.hasSuffix("-----") else { -// throw NSError(domain: "Invalid PEM Format", code: 0, userInfo: nil) -// } -// -// //print("Attempting to decode: \(chunks[1.. Date: Sun, 18 Sep 2022 00:21:37 -0700 Subject: [PATCH 44/52] Removed unused code --- .../Keys/Types/RSA/RSA+CryptoSwift.swift | 103 +----------------- 1 file changed, 2 insertions(+), 101 deletions(-) diff --git a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift index bdaa3c2..86ace21 100644 --- a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift +++ b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+CryptoSwift.swift @@ -126,8 +126,8 @@ struct RSAPrivateKey:CommonPrivateKey { } var rawRepresentation: Data { - guard key.d != nil else { /*throw NSError(domain: "Not a valid private RSA Key", code: 0)*/ return Data() } - return try! self.key.externalRepresentation() + guard key.d != nil, let raw = try? self.key.externalRepresentation() else { return Data() } + return raw } func derivePublicKey() throws -> CommonPublicKey { @@ -170,17 +170,7 @@ extension CryptoSwift.RSA { /// - Note: The signature uses the SHA256 PKCS#1v15 Padding Scheme /// - Note: [EMSA-PKCS1-v1_5](https://datatracker.ietf.org/doc/html/rfc8017#section-9.2) fileprivate static func sign(message:Data, withKey key:RSA) throws -> Data { - return try Data(key.sign(message.bytes, variant: .message_pkcs1v15_SHA256)) - -// guard let d = key.d else { throw NSError(domain: "Signing data requires a Private RSA key", code: 0) } -// let encodedMessage = try CryptoSwift.RSA.hashedAndPKCSEncoded(message.bytes, modLength: key.n.serialize().count) -// -// let n = BigUInteger(Data(encodedMessage)) -// let e = d -// let m = key.n -// let signedData_RsaKey = CryptoSwift.RSA.modPow(n: n, e: e, m: m).serialize() -// return signedData_RsaKey } /// Verifies a signature for the expected data @@ -188,97 +178,8 @@ extension CryptoSwift.RSA { /// - Note: This method assumes the signature was generated using the SHA256 PKCS#1v15 Padding Scheme /// - Note: [EMSA-PKCS1-v1_5](https://datatracker.ietf.org/doc/html/rfc8017#section-9.2) fileprivate static func verify(signature:Data, fromMessage message:Data, usingKey key:RSA) throws -> Bool { - return try key.verify(signature: signature.bytes, for: message.bytes, variant: .message_pkcs1v15_SHA256) - -// let modLength = key.n.serialize().count -// /// Step 1: Ensure the signature is the same length as the key's modulus -// guard signature.count == modLength else { throw NSError(domain: "Invalid Signature Length", code: 0) } -// -// /// Step 2: 'Decrypt' the signature -// let n = BigUInteger(signature) -// let e = key.e -// let m = key.n -// let pkcsEncodedSHA256HashedMessage = CryptoSwift.RSA.modPow(n: n, e: e, m: m).serialize() -// -// /// Step 3: Compare the 'decrypted' signature with the prepared / encoded expected message.... -// let preparedExpectedMessage = try CryptoSwift.RSA.hashedAndPKCSEncoded(message.bytes, modLength: modLength).dropFirst() -// -// guard pkcsEncodedSHA256HashedMessage == preparedExpectedMessage else { return false } -// -// return true } - - /// prepends the data with zero's until it reaches the specified length -// fileprivate static func zeroPad(n:[UInt8], to:Int) -> [UInt8] { -// var modulus = n -// while modulus.count < to { -// modulus.insert(0x00, at: 0) -// } -// return modulus -// } - - /// Modular exponentiation - /// - /// - Credit: AttaSwift BigInt - /// - Source: https://rosettacode.org/wiki/Modular_exponentiation#Swift -// fileprivate static func modPow(n: T, e: T, m: T) -> T { -// guard e != 0 else { -// return 1 -// } -// -// var res = T(1) -// var base = n % m -// var exp = e -// -// while true { -// if exp & 1 == 1 { -// res *= base -// res %= m -// } -// -// if exp == 1 { -// return res -// } -// -// exp /= 2 -// base *= base -// base %= m -// } -// } - - /// Hashes and Encodes a message for signing and verifying - /// - /// - Note: [EMSA-PKCS1-v1_5](https://datatracker.ietf.org/doc/html/rfc8017#section-9.2) -// fileprivate static func hashedAndPKCSEncoded(_ message:[UInt8], modLength:Int) throws -> Data { -// /// 1. Apply the hash function to the message M to produce a hash -// let hashedMessage = SHA2(variant: .sha256).calculate(for: message) -// -// /// 2. Encode the algorithm ID for the hash function and the hash value into an ASN.1 value of type DigestInfo -// /// PKCS#1_15 DER Structure (OID == sha256WithRSAEncryption) -// let asn:ASN1.Node = .sequence(nodes: [ -// .sequence(nodes: [ -// .objectIdentifier(data: Data(Array(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01))), -// .null -// ]), -// .octetString(data: Data(hashedMessage)) -// ]) -// -// let t = ASN1.Encoder.encode(asn) -// -// /// 3. If emLen < tLen + 11, output "intended encoded message lengthtoo short" and stop -// if modLength < t.count + 11 { throw NSError(domain: "intended encoded message length too short", code: 0) } -// -// /// 4. Generate an octet string PS consisting of emLen - tLen - 3 -// /// octets with hexadecimal value 0xff. The length of PS will be -// /// at least 8 octets. -// let r = modLength - t.count - 3 -// let padding = [0x00, 0x01] + Array(repeating: 0xFF, count: r) + [0x00] -// -// /// 5. Concatenate PS, the DER encoding T, and other padding to form -// /// the encoded message EM as EM = 0x00 || 0x01 || PS || 0x00 || T. -// return Data(padding + t) -// } } #endif From c2813b33fa9b65e1263534889e8fc513bd5b909b Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 18 Sep 2022 00:24:02 -0700 Subject: [PATCH 45/52] Removed JWT and RSAPublicKeyExporter/Importer --- Package.swift | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Package.swift b/Package.swift index a028956..ed99939 100644 --- a/Package.swift +++ b/Package.swift @@ -20,8 +20,6 @@ let package = Package( .package(url: "https://github.com/swift-libp2p/swift-multibase.git", .upToNextMajor(from: "0.0.1")), // Protobuf Marshaling .package(url: "https://github.com/apple/swift-protobuf.git", .upToNextMajor(from: "1.12.0")), - // RSA Import / Export Support - //.package(url: "https://github.com/nextincrement/rsa-public-key-importer-exporter.git", .upToNextMajor(from: "0.1.0")), // Secp256k1 Support .package(url: "https://github.com/Boilertalk/secp256k1.swift.git", .exact("0.1.6")), // 🔑 Hashing (BCrypt, SHA2, HMAC), encryption (AES), public-key (RSA), PEM and DER file handling, and random data generation. @@ -29,7 +27,7 @@ let package = Package( .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMajor(from: "1.5.0")), .package(url: "https://github.com/swift-libp2p/swift-multihash.git", .upToNextMajor(from: "0.0.1")), // JWT Support - .package(url: "https://github.com/vapor/jwt-kit.git", .upToNextMajor(from: "4.0.0")) + //.package(url: "https://github.com/vapor/jwt-kit.git", .upToNextMajor(from: "4.0.0")) ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. @@ -40,12 +38,10 @@ let package = Package( .product(name: "Multibase", package: "swift-multibase"), .product(name: "Multihash", package: "swift-multihash"), .product(name: "SwiftProtobuf", package: "swift-protobuf"), - //.product(name: "RSAPublicKeyExporter", package: "rsa-public-key-importer-exporter"), - //.product(name: "RSAPublicKeyImporter", package: "rsa-public-key-importer-exporter"), .product(name: "secp256k1", package: "secp256k1.swift"), .product(name: "Crypto", package: "swift-crypto"), .product(name: "CryptoSwift", package: "CryptoSwift"), - .product(name: "JWTKit", package: "jwt-kit") + //.product(name: "JWTKit", package: "jwt-kit") ], resources: [ .copy("Protobufs/keys.proto") From 2bcb1aea0441af1657455c619e23bdacd3852d58 Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 18 Sep 2022 00:29:00 -0700 Subject: [PATCH 46/52] Capitalized file name --- Tests/LibP2PCryptoTests/fixtures.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/LibP2PCryptoTests/fixtures.swift b/Tests/LibP2PCryptoTests/fixtures.swift index c3ee991..dc43fe7 100644 --- a/Tests/LibP2PCryptoTests/fixtures.swift +++ b/Tests/LibP2PCryptoTests/fixtures.swift @@ -1,5 +1,5 @@ // -// fixtures.swift +// Fixtures.swift // // // Created by Brandon Toms on 6/6/22. From de59b92447bb6c14385075c49f8e070e35c5ad0a Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 18 Sep 2022 10:40:35 -0700 Subject: [PATCH 47/52] Bumped CryptoSwift version to 1.6.+ --- Package.swift | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Package.swift b/Package.swift index 754784c..bd33dac 100644 --- a/Package.swift +++ b/Package.swift @@ -17,17 +17,15 @@ let package = Package( ], dependencies: [ // Multibase Support - .package(url: "https://github.com/swift-libp2p/swift-multibase.git", .upToNextMajor(from: "0.0.1")), + .package(url: "https://github.com/swift-libp2p/swift-multibase.git", .upToNextMinor(from: "0.0.1")), // Protobuf Marshaling .package(url: "https://github.com/apple/swift-protobuf.git", .upToNextMajor(from: "1.12.0")), // Secp256k1 Support .package(url: "https://github.com/Boilertalk/secp256k1.swift.git", .exact("0.1.6")), // 🔑 Hashing (BCrypt, SHA2, HMAC), encryption (AES), public-key (RSA), PEM and DER file handling, and random data generation. .package(url: "https://github.com/apple/swift-crypto.git", .upToNextMajor(from: "1.0.0")), - .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .exact("1.5.1")), - .package(url: "https://github.com/swift-libp2p/swift-multihash.git", .upToNextMajor(from: "0.0.1")), - // JWT Support - //.package(url: "https://github.com/vapor/jwt-kit.git", .upToNextMajor(from: "4.0.0")) + .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.6.0")), + .package(url: "https://github.com/swift-libp2p/swift-multihash.git", .upToNextMinor(from: "0.0.1")), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. @@ -41,7 +39,6 @@ let package = Package( .product(name: "secp256k1", package: "secp256k1.swift"), .product(name: "Crypto", package: "swift-crypto"), .product(name: "CryptoSwift", package: "CryptoSwift"), - //.product(name: "JWTKit", package: "jwt-kit") ], resources: [ .copy("Protobufs/keys.proto") From 2cf230d9e3d48836a1b9418d42a5cecdc215f45c Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 18 Sep 2022 13:08:06 -0700 Subject: [PATCH 48/52] Removed print statements --- Sources/LibP2PCrypto/PEM/PEM.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/LibP2PCrypto/PEM/PEM.swift b/Sources/LibP2PCrypto/PEM/PEM.swift index e6406a5..9166f09 100644 --- a/Sources/LibP2PCrypto/PEM/PEM.swift +++ b/Sources/LibP2PCrypto/PEM/PEM.swift @@ -198,8 +198,8 @@ struct PEM { internal static func decodePublicKeyPEM(_ pem:Data, expectedPrimaryObjectIdentifier:Array, expectedSecondaryObjectIdentifier:Array?) throws -> Array { let asn = try ASN1.Decoder.decode(data: pem) - print("PublicKey") - print(asn) + //print("PublicKey") + //print(asn) // Enforce the above ASN1 Structure guard case .sequence(let sequence) = asn else { throw Error.invalidPEMFormat("PublicKey::No top level sequence for PublicKey PEM") } @@ -231,14 +231,14 @@ struct PEM { internal static func decodePrivateKeyPEM(_ pem:Data, expectedPrimaryObjectIdentifier:Array, expectedSecondaryObjectIdentifier:Array?) throws -> Array { let asn = try ASN1.Decoder.decode(data: pem) - print("PrivateKey") - print(asn) + //print("PrivateKey") + //print(asn) // Enforce the above ASN1 Structure guard case .sequence(let sequence) = asn else { throw Error.invalidPEMFormat("PrivateKey::Top level node is not a sequence") } // Enforce the integer/version param as the first param in our top level sequence guard case .integer(let integer) = sequence.first else { throw Error.invalidPEMFormat("PrivateKey::First item in top level sequence wasn't an integer") } - print("PEM Version: \(integer.bytes)") + //print("PEM Version: \(integer.bytes)") switch integer { case Data(hex: "0x00"): //Proceed with standard pkcs1 private key format From d8dff27a604079e3e7a7fc65d3c6008ec8fc110c Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 18 Sep 2022 13:22:39 -0700 Subject: [PATCH 49/52] Wrapped fixture generation tests in Security canImport --- Tests/LibP2PCryptoTests/FixtureGenerationTests.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/LibP2PCryptoTests/FixtureGenerationTests.swift b/Tests/LibP2PCryptoTests/FixtureGenerationTests.swift index 4ec9733..e3c4884 100644 --- a/Tests/LibP2PCryptoTests/FixtureGenerationTests.swift +++ b/Tests/LibP2PCryptoTests/FixtureGenerationTests.swift @@ -5,6 +5,7 @@ // Created by Brandon Toms on 7/7/22. // +#if canImport(Security) import XCTest @testable import LibP2PCrypto @@ -276,6 +277,7 @@ static let {{KEY_TYPE}}{{KEY_SIZE}} = Fixture( } } +#endif struct TestFixtures { struct Fixture { From e199b667b84616c25f0a3df6208d0466a7a74386 Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 18 Sep 2022 13:29:14 -0700 Subject: [PATCH 50/52] Removed FixtureGenerationTest --- .../FixtureGenerationTests.swift | 297 ------------------ Tests/LibP2PCryptoTests/fixtures.swift | 17 + 2 files changed, 17 insertions(+), 297 deletions(-) delete mode 100644 Tests/LibP2PCryptoTests/FixtureGenerationTests.swift diff --git a/Tests/LibP2PCryptoTests/FixtureGenerationTests.swift b/Tests/LibP2PCryptoTests/FixtureGenerationTests.swift deleted file mode 100644 index e3c4884..0000000 --- a/Tests/LibP2PCryptoTests/FixtureGenerationTests.swift +++ /dev/null @@ -1,297 +0,0 @@ -// -// FixtureGenerationTests.swift -// -// -// Created by Brandon Toms on 7/7/22. -// - -#if canImport(Security) -import XCTest -@testable import LibP2PCrypto - -final class FixtureGenerationTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testCreateRSATestFixture() throws { - - let fixtures = [1024, 2048, 3072, 4096] - let keyType = "RSA" - - for fixture in fixtures { - let keySize = fixture - let message = "LibP2P RSA Keys!" - - /// Generate a SecKey RSA Key - let parameters: [CFString: Any] = [ - kSecAttrKeyType: kSecAttrKeyTypeRSA, - kSecAttrKeySizeInBits: keySize - ] - - var error: Unmanaged? - - // Generate the RSA SecKey - guard let rsaSecKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else { - XCTFail("Key Generation Error: \(error.debugDescription)") - return - } - - // Extract the public key from the private RSA SecKey - guard let rsaSecKeyPublic = SecKeyCopyPublicKey(rsaSecKey) else { - XCTFail("Public Key Extraction Error") - return - } - - /// Lets grab the external representation of the public key - var publicExternalRepError: Unmanaged? - guard let publicRSASecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKeyPublic, &publicExternalRepError) as? Data else { - XCTFail("Failed to copy external representation for RSA SecKey") - return - } - - /// Lets grab the external representation of the public key - var privateExternalRepError: Unmanaged? - guard let privateRSASecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &privateExternalRepError) as? Data else { - XCTFail("Failed to copy external representation for RSA SecKey") - return - } - - guard let rsaKey = try? RSAPrivateKey(rawRepresentation: privateRSASecKeyRawRep) else { - XCTFail("Failed to import SecKey as RSAPrivateKey") - return - } - - var template = FixtureTemplate - template = template.replacingOccurrences(of: "{{KEY_TYPE}}", with: keyType) - template = template.replacingOccurrences(of: "{{KEY_SIZE}}", with: "_\(keySize)") - - // DERs - template = template.replacingOccurrences(of: "{{PUBLIC_DER}}", with: "\(publicRSASecKeyRawRep.base64EncodedString())") - template = template.replacingOccurrences(of: "{{PRIVATE_DER}}", with: "\(privateRSASecKeyRawRep.base64EncodedString())") - - // PEMs - template = template.replacingOccurrences(of: "{{PUBLIC_PEM}}", with: try rsaKey.exportPublicKeyPEMString(withHeaderAndFooter: true)) - template = template.replacingOccurrences(of: "{{PRIVATE_PEM}}", with: try rsaKey.exportPrivateKeyPEMString(withHeaderAndFooter: true)) - - // Encrypted PEMs - template = template.replacingOccurrences(of: "{{ENCRYPTED_PEMS}}", with: "") - template = template.replacingOccurrences(of: "{{ENCRYPTION_PASSWORD}}", with: "") - - // Marshaled - template = template.replacingOccurrences(of: "{{PUBLIC_MARSHALED}}", with: try rsaKey.derivePublicKey().marshal().base64EncodedString()) - template = template.replacingOccurrences(of: "{{PRIVATE_MARSHALED}}", with: try rsaKey.marshal().base64EncodedString()) - - // Plaintext Message - template = template.replacingOccurrences(of: "{{PLAINTEXT_MESSAGE}}", with: message) - - let encryptedMessages = try encrypt(data: message.data(using: .utf8)!, with: rsaSecKeyPublic) - template = template.replacingOccurrences(of: "{{ENCRYPTED_MESSAGES}}", with: encryptedMessages.joined(separator: ",\n\t ")) - - let signedMessages = try sign(message: message.data(using: .utf8)!, using: rsaSecKey) - template = template.replacingOccurrences(of: "{{SIGNED_MESSAGES}}", with: signedMessages.joined(separator: ",\n\t ")) - - print(template) - } - } - - func testCreateED25519TestFixture() throws { - - let message = "LibP2P ED25519 Keys!" - let keySize:Int? = nil - let keyType = "ED25519" - - // Generate the RSA SecKey - guard let edKey = try? LibP2PCrypto.Keys.KeyPair(.Ed25519) else { - XCTFail("Key Generation Error") - return - } - - var template = FixtureTemplate - template = template.replacingOccurrences(of: "{{KEY_TYPE}}", with: keyType) - template = template.replacingOccurrences(of: "{{KEY_SIZE}}", with: keySize != nil ? "_\(keySize!)" : "") - - // DERs - template = template.replacingOccurrences(of: "{{PUBLIC_DER}}", with: "\(try edKey.publicKey.publicKeyDER().asString(base: .base64Pad))") - template = template.replacingOccurrences(of: "{{PRIVATE_DER}}", with: "\(try edKey.privateKey!.privateKeyDER().asString(base: .base64Pad))") - - // PEMs - template = template.replacingOccurrences(of: "{{PUBLIC_PEM}}", with: try edKey.exportPublicPEMString(withHeaderAndFooter: true)) - template = template.replacingOccurrences(of: "{{PRIVATE_PEM}}", with: try edKey.exportPrivatePEMString(withHeaderAndFooter: true)) - - // Encrypted PEMs - template = template.replacingOccurrences(of: "{{ENCRYPTED_PEMS}}", with: "") - template = template.replacingOccurrences(of: "{{ENCRYPTION_PASSWORD}}", with: "") - - // Marshaled - template = template.replacingOccurrences(of: "{{PUBLIC_MARSHALED}}", with: try edKey.publicKey.marshal().base64EncodedString()) - template = template.replacingOccurrences(of: "{{PRIVATE_MARSHALED}}", with: try edKey.privateKey!.marshal().base64EncodedString()) - - // Plaintext Message - template = template.replacingOccurrences(of: "{{PLAINTEXT_MESSAGE}}", with: message) - - // TODO: Add algorithm prefix - let encryptedMessages = [try edKey.encrypt(data: message.data(using: .utf8)!).base64EncodedString()] - template = template.replacingOccurrences(of: "{{ENCRYPTED_MESSAGES}}", with: encryptedMessages.joined(separator: ",\n\t ")) - - let signedMessages = [try edKey.sign(message: message.data(using: .utf8)!).base64EncodedString()] - template = template.replacingOccurrences(of: "{{SIGNED_MESSAGES}}", with: signedMessages.joined(separator: ",\n\t ")) - -// let encryptedMessages = try encrypt(data: message.data(using: .utf8)!, with: edKey) -// template = template.replacingOccurrences(of: "{{ENCRYPTED_MESSAGES}}", with: encryptedMessages.joined(separator: ",\n\t ")) -// -// let signedMessages = try sign(message: message.data(using: .utf8)!, using: edKey) -// template = template.replacingOccurrences(of: "{{SIGNED_MESSAGES}}", with: signedMessages.joined(separator: ",\n\t ")) - - print(template) - } - - private let FixtureTemplate = """ -static let {{KEY_TYPE}}{{KEY_SIZE}} = Fixture( - keySize: {{KEY_SIZE}}, - publicDER: \"\"\" -{{PUBLIC_DER}} -\"\"\", - privateDER: \"\"\" -{{PRIVATE_DER}} -\"\"\", - publicPEM: \"\"\" -{{PUBLIC_PEM}} -\"\"\", - privatePEM: \"\"\" -{{PRIVATE_PEM}} -\"\"\", - encryptedPEM: [ -{{ENCRYPTED_PEMS}} - ], - encryptionPassword: \"{{ENCRYPTION_PASSWORD}}\", - publicMarshaled: \"\"\" -{{PUBLIC_MARSHALED}} -\"\"\", - privateMarshaled: \"\"\" -{{PRIVATE_MARSHALED}} -\"\"\", - rawMessage: "{{PLAINTEXT_MESSAGE}}", - encryptedMessage: [ - {{ENCRYPTED_MESSAGES}} - ], - signedMessages: [ - {{SIGNED_MESSAGES}} - ] -) -""" - - //private func printHexData16BytesWide(_ bytes:[UInt8]) { -// print(bytes.toHexString().split(intoChunksOfLength: 32).map { $0.split(intoChunksOfLength: 2).map { "0x\($0.uppercased())" }.joined(separator: ", ") }.joined(separator: ",\n")) - //} - - private func initSecKey(rawRepresentation raw: Data) throws -> SecKey { - let attributes: [String: Any] = [ - kSecAttrKeyType as String: kSecAttrKeyTypeRSA, - kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, - kSecAttrKeySizeInBits as String: 1024, - kSecAttrIsPermanent as String: false - ] - - var error: Unmanaged? - guard let secKey = SecKeyCreateWithData(raw as CFData, attributes as CFDictionary, &error) else { - throw NSError(domain: "Error constructing SecKey from raw key data: \(error.debugDescription)", code: 0, userInfo: nil) - } - - return secKey - } - - /// https://datatracker.ietf.org/doc/html/rfc8017#section-9.1 - private func sign(message: Data, using key: SecKey) throws -> [String] { - let algorithms: [SecKeyAlgorithm] = [ - .rsaSignatureRaw, - //.rsaSignatureDigestPSSSHA1, - //.rsaSignatureDigestPSSSHA224, - //.rsaSignatureDigestPSSSHA256, - //.rsaSignatureDigestPSSSHA384, - //.rsaSignatureDigestPSSSHA512, - .rsaSignatureDigestPKCS1v15Raw, - .rsaSignatureDigestPKCS1v15SHA1, - .rsaSignatureDigestPKCS1v15SHA224, - .rsaSignatureDigestPKCS1v15SHA256, - .rsaSignatureDigestPKCS1v15SHA384, - .rsaSignatureDigestPKCS1v15SHA512, - //.rsaSignatureMessagePSSSHA1, - //.rsaSignatureMessagePSSSHA224, - //.rsaSignatureMessagePSSSHA256, - //.rsaSignatureMessagePSSSHA384, - //.rsaSignatureMessagePSSSHA512, - .rsaSignatureMessagePKCS1v15SHA1, - .rsaSignatureMessagePKCS1v15SHA224, - .rsaSignatureMessagePKCS1v15SHA256, - .rsaSignatureMessagePKCS1v15SHA384, - .rsaSignatureMessagePKCS1v15SHA512, - ] - - var sigs: [String] = [] - - for algo in algorithms { - var error: Unmanaged? - - // Sign the data - guard let signature = SecKeyCreateSignature( - key, - algo, - message as CFData, - &error - ) as Data? - else { print("\"\(algo.rawValue)\": \"nil\","); continue } - - // Throw the error if we encountered one - if let error = error { print("\"\(algo.rawValue)\": \"\(error.takeRetainedValue())\","); continue } - - // Append the signature - sigs.append("\"\(algo.rawValue)\": \"\(signature.base64EncodedString())\"") - } - - return sigs - } - - private func encrypt(data: Data, with key: SecKey) throws -> [String] { - let algorithms: [SecKeyAlgorithm] = [ - .rsaEncryptionRaw, - .rsaEncryptionPKCS1 - ] - - var encryptions: [String] = [] - - for algo in algorithms { - var error: Unmanaged? - guard let encryptedData = SecKeyCreateEncryptedData(key, algo, data as CFData, &error) as? Data else { - print("\"\(algo.rawValue)\": \"\(error?.takeRetainedValue().localizedDescription ?? "nil")\","); continue - } - encryptions.append("\"\(algo.rawValue)\": \"\(encryptedData.base64EncodedString())\"") - } - - return encryptions - } - -} -#endif - -struct TestFixtures { - struct Fixture { - let keySize: Int - let publicDER: String - let privateDER: String - let publicPEM:String - let privatePEM:String - let encryptedPEM:[String:String] - let encryptionPassword:String - let publicMarshaled:String - let privateMarshaled:String - let rawMessage: String - let encryptedMessage: [String: String] - let signedMessages: [String: String] - } -} diff --git a/Tests/LibP2PCryptoTests/fixtures.swift b/Tests/LibP2PCryptoTests/fixtures.swift index dc43fe7..cd2b276 100644 --- a/Tests/LibP2PCryptoTests/fixtures.swift +++ b/Tests/LibP2PCryptoTests/fixtures.swift @@ -7,6 +7,23 @@ import Foundation +struct TestFixtures { + struct Fixture { + let keySize: Int + let publicDER: String + let privateDER: String + let publicPEM:String + let privatePEM:String + let encryptedPEM:[String:String] + let encryptionPassword:String + let publicMarshaled:String + let privateMarshaled:String + let rawMessage: String + let encryptedMessage: [String: String] + let signedMessages: [String: String] + } +} + extension TestFixtures { static let RSA_1024 = Fixture( keySize: 1024, From 2e305549b61b66ff6040f498b0bfa436784979be Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 18 Sep 2022 13:41:35 -0700 Subject: [PATCH 51/52] Removed canImport test within exportPrivateKeyPEMRaw method --- Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift index b5b5535..81fc80d 100644 --- a/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift +++ b/Sources/LibP2PCrypto/Keys/Types/RSA/RSA+DER.swift @@ -70,7 +70,6 @@ extension RSAPrivateKey: DERCodable { } public func exportPrivateKeyPEMRaw() throws -> Array { - #if canImport(Security) let privateDER = try self.privateKeyDER() let asnNodes:ASN1.Node = .sequence(nodes: [ .integer(data: Data(hex: "0x00")), @@ -82,9 +81,6 @@ extension RSAPrivateKey: DERCodable { ]) return ASN1.Encoder.encode(asnNodes) - #else - throw NSError(domain: "CryptoSwift doesn't support exporting private keys yet", code: 0) - #endif } public func exportPrivateKeyPEM(withHeaderAndFooter: Bool) throws -> Array { From 69458600305943a3d1aa5b5b5cd67ba845463f4d Mon Sep 17 00:00:00 2001 From: Brandon Toms Date: Sun, 18 Sep 2022 13:45:16 -0700 Subject: [PATCH 52/52] Added an additional attributes case --- Sources/LibP2PCrypto/Keys/KeyPair.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/LibP2PCrypto/Keys/KeyPair.swift b/Sources/LibP2PCrypto/Keys/KeyPair.swift index 3fc4e7b..e414004 100644 --- a/Sources/LibP2PCrypto/Keys/KeyPair.swift +++ b/Sources/LibP2PCrypto/Keys/KeyPair.swift @@ -89,7 +89,7 @@ extension LibP2PCrypto.Keys { case .rsa: let count = self.publicKey.rawRepresentation.count switch self.publicKey.rawRepresentation.count { - case 140, 162: + case 140, 161, 162: return Attributes(type: .RSA(bits: .B1024), size: 1024, isPrivate: (self.privateKey != nil)) case 270, 294: return Attributes(type: .RSA(bits: .B2048), size: 2048, isPrivate: (self.privateKey != nil))