Explorar o código

Core of RSA encrypt/decrypt

Nathan Fallet %!s(int64=4) %!d(string=hai) anos
pai
achega
3748f277b6
Modificáronse 2 ficheiros con 67 adicións e 35 borrados
  1. 20 12
      Sources/CryptoSwift/GiantUInt.swift
  2. 47 23
      Sources/CryptoSwift/RSA.swift

+ 20 - 12
Sources/CryptoSwift/GiantUInt.swift

@@ -16,15 +16,15 @@
 precedencegroup PowerPrecedence { higherThan: MultiplicationPrecedence }
 infix operator ^^ : PowerPrecedence
 
-struct GiantUInt: Equatable, Comparable, ExpressibleByIntegerLiteral {
+public struct GiantUInt: Equatable, Comparable, ExpressibleByIntegerLiteral, ExpressibleByArrayLiteral {
   
   // Properties
   
-  let bytes: Array<UInt8>
+  public let bytes: Array<UInt8>
   
   // Initialization
   
-  init(_ raw: Array<UInt8>) {
+  public init(_ raw: Array<UInt8>) {
     var bytes = raw
     
     while bytes.last == 0 {
@@ -36,21 +36,29 @@ struct GiantUInt: Equatable, Comparable, ExpressibleByIntegerLiteral {
   
   // ExpressibleByIntegerLiteral
   
-  typealias IntegerLiteralType = UInt8
+  public typealias IntegerLiteralType = UInt8
   
-  init(integerLiteral value: UInt8) {
+  public init(integerLiteral value: UInt8) {
     self = GiantUInt([value])
   }
+  
+  // ExpressibleByArrayLiteral
+  
+  public typealias ArrayLiteralElement = UInt8
+  
+  public init(arrayLiteral elements: UInt8...) {
+    self = GiantUInt(elements)
+  }
     
   // Equatable
   
-  static func == (lhs: GiantUInt, rhs: GiantUInt) -> Bool {
+  public static func == (lhs: GiantUInt, rhs: GiantUInt) -> Bool {
     lhs.bytes == rhs.bytes
   }
   
   // Comparable
   
-  static func < (rhs: GiantUInt, lhs: GiantUInt) -> Bool {
+  public static func < (rhs: GiantUInt, lhs: GiantUInt) -> Bool {
     for i in (0 ..< max(rhs.bytes.count, lhs.bytes.count)).reversed() {
       let r = rhs.bytes[safe: i] ?? 0
       let l = lhs.bytes[safe: i] ?? 0
@@ -66,7 +74,7 @@ struct GiantUInt: Equatable, Comparable, ExpressibleByIntegerLiteral {
   
   // Operations
   
-  static func + (rhs: GiantUInt, lhs: GiantUInt) -> GiantUInt {
+  public static func + (rhs: GiantUInt, lhs: GiantUInt) -> GiantUInt {
     var bytes = [UInt8]()
     var r: UInt8 = 0
     
@@ -83,7 +91,7 @@ struct GiantUInt: Equatable, Comparable, ExpressibleByIntegerLiteral {
     return GiantUInt(bytes)
   }
   
-  static func - (rhs: GiantUInt, lhs: GiantUInt) -> GiantUInt {
+  public static func - (rhs: GiantUInt, lhs: GiantUInt) -> GiantUInt {
     var bytes = [UInt8]()
     var r: UInt8 = 0
     
@@ -102,7 +110,7 @@ struct GiantUInt: Equatable, Comparable, ExpressibleByIntegerLiteral {
     return GiantUInt(bytes)
   }
   
-  static func * (rhs: GiantUInt, lhs: GiantUInt) -> GiantUInt {
+  public static func * (rhs: GiantUInt, lhs: GiantUInt) -> GiantUInt {
     var offset = 0
     var sum = [GiantUInt]()
     
@@ -127,7 +135,7 @@ struct GiantUInt: Equatable, Comparable, ExpressibleByIntegerLiteral {
     return sum.reduce(0, +)
   }
   
-  static func % (rhs: GiantUInt, lhs: GiantUInt) -> GiantUInt {
+  public static func % (rhs: GiantUInt, lhs: GiantUInt) -> GiantUInt {
     var remainder = rhs
     
     // This needs serious optimization (but works)
@@ -157,7 +165,7 @@ struct GiantUInt: Equatable, Comparable, ExpressibleByIntegerLiteral {
     return result
   }
   
-  static func exponentiateWithModulus(rhs: GiantUInt, lhs: GiantUInt, modulus: GiantUInt) -> GiantUInt {
+  public static func exponentiateWithModulus(rhs: GiantUInt, lhs: GiantUInt, modulus: GiantUInt) -> GiantUInt {
     let count = lhs.bytes.count
     var result = GiantUInt([1])
     

+ 47 - 23
Sources/CryptoSwift/RSA.swift

@@ -16,33 +16,52 @@
 public final class RSA {
   
   public enum Error: Swift.Error {
-    /// Invalid key
-    case invalidKey
+    /// No private key specified
+    case noPrivateKey
   }
   
-  let publicKey: Key?
-  let privateKey: Key?
+  /// RSA Modulus
+  public let n: GiantUInt
   
-  public var keySize: Int = 0
+  /// RSA Public Exponent
+  public let e: GiantUInt
   
-  public init(publicKey: Array<UInt8>?, privateKey: Array<UInt8>?) throws {
-    if let publicKey = publicKey {
-      self.publicKey = Key(bytes: publicKey)
-      self.keySize = self.publicKey!.count
-    } else {
-      self.publicKey = nil
-    }
-    if let privateKey = privateKey {
-      self.privateKey = Key(bytes: privateKey)
-      self.keySize = self.privateKey!.count
+  /// RSA Private Exponent
+  public let d: GiantUInt?
+  
+  /// The size of the modulus, in bits
+  public let keySize: Int
+  
+  /// Initialize with RSA parameters
+  /// - Parameters:
+  ///   - n: The RSA Modulus
+  ///   - e: The RSA Public Exponent
+  ///   - d: The RSA Private Exponent (or nil if unknown, e.g. if only public key is known)
+  public init(n: GiantUInt, e: GiantUInt, d: GiantUInt? = nil) {
+    self.n = n
+    self.e = e
+    self.d = d
+    
+    self.keySize = n.bytes.count * 8
+  }
+  
+  /// Initialize with RSA parameters
+  /// - Parameters:
+  ///   - n: The RSA Modulus
+  ///   - e: The RSA Public Exponent
+  ///   - d: The RSA Private Exponent (or nil if unknown, e.g. if only public key is known)
+  public convenience init(n: Array<UInt8>, e: Array<UInt8>, d: Array<UInt8>? = nil) {
+    if let d = d {
+      self.init(n: GiantUInt(n), e: GiantUInt(e), d: GiantUInt(d))
     } else {
-      self.privateKey = nil
-    }
-    if keySize == 0 {
-      throw RSA.Error.invalidKey
+      self.init(n: GiantUInt(n), e: GiantUInt(e))
     }
   }
   
+  // TODO: Add initializer from PEM (ASN.1 with DER header)
+  
+  // TODO: Add export to PEM (ASN.1 with DER header)
+  
 }
 
 // MARK: Cipher
@@ -51,14 +70,19 @@ extension RSA: Cipher {
   
   @inlinable
   public func encrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
-    // TODO
-    return []
+    // Calculate encrypted data
+    return GiantUInt.exponentiateWithModulus(rhs: GiantUInt(Array(bytes)), lhs: e, modulus: n).bytes
   }
 
   @inlinable
   public func decrypt(_ bytes: ArraySlice<UInt8>) throws -> Array<UInt8> {
-    // TODO
-    return []
+    // Check for Private Exponent presence
+    guard let d = d else {
+      throw RSA.Error.noPrivateKey
+    }
+    
+    // Calculate decrypted data
+    return GiantUInt.exponentiateWithModulus(rhs: GiantUInt(Array(bytes)), lhs: d, modulus: n).bytes
   }
   
 }