2017-09-15 86 views
-2

Download XCode projectRSA加密文件或文本

enter image description here

我加密消息,並將其保存到文件中。如果我在加密文件的同時解密文件,解密成功但是如果其他時間解密函數返回零。

我使用這個類來加密和解密。

class Crypt{ 

    // MARK: Public 

    // MARK: Internal 
    var publicKey, privateKey: SecKey? 
    var publicKeyData, privateKeyData: Data? 
    var statusCode: OSStatus? 


    let publicKeyAttr: [NSObject: NSObject] = [ 
     kSecAttrIsPermanent:true as NSObject, 
     kSecAttrApplicationTag:"com.aparnik.ios.books.public".data(using: String.Encoding.utf8)! as NSObject, 
     kSecClass: kSecClassKey, // added this value 
     kSecReturnData: kCFBooleanTrue] // added this value 
    let privateKeyAttr: [NSObject: NSObject] = [ 
     kSecAttrIsPermanent:true as NSObject, 
     kSecAttrApplicationTag:"com.aparnik.ios.books.private".data(using: String.Encoding.utf8)! as NSObject, 
     kSecClass: kSecClassKey, // added this value 
     kSecReturnData: kCFBooleanTrue] // added this value 

    // MARK: Private 

    // MARK: Initializer 
    init() { 
     self.generateRSAKey() 
    } 

    // MARK: Function 
    fileprivate func generateRSAKey() { 

     var keyPairAttr = [NSObject: NSObject]() 
     keyPairAttr[kSecAttrKeyType] = kSecAttrKeyTypeRSA 
     keyPairAttr[kSecAttrKeySizeInBits] = 1024 as NSObject 
     keyPairAttr[kSecPublicKeyAttrs] = publicKeyAttr as NSObject 
     keyPairAttr[kSecPrivateKeyAttrs] = privateKeyAttr as NSObject 

     statusCode = SecKeyGeneratePair(keyPairAttr as CFDictionary, &publicKey, &privateKey) 

     if statusCode == noErr && self.publicKey != nil && self.privateKey != nil { 
      print("Key pair generated OK") 
      var resultPublicKey: AnyObject? 
      var resultPrivateKey: AnyObject? 
      let statusPublicKey = SecItemCopyMatching(publicKeyAttr as CFDictionary, &resultPublicKey) 
      let statusPrivateKey = SecItemCopyMatching(privateKeyAttr as CFDictionary, &resultPrivateKey) 

      if statusPublicKey == noErr { 
       if let publicKeyData = resultPublicKey as? Data { 
        self.publicKeyData = publicKeyData 
//     let publicKeyXor = xor(publicKeyData) 
        //print("Public Key: \((publicKeyData.base64EncodedString()))") 
        //print("Public Key xor: \(publicKeyXor.base64EncodedString())") 

       } 
      } 

      if statusPrivateKey == noErr { 
       if let privateKey = resultPrivateKey as? Data { 
        self.privateKeyData = privateKey 
        //print("Private Key: \((privateKey.base64EncodedString()))" 
       } 
      } 
     } else { 
      //print("Error generating key pair: \(String(describing: statusCode))") 
     } 
    } 


    func xor() -> Data{ 

     var publicKeyXor: Data = Data() 

      if (self.publicKeyData != nil) { 

       //print("Public Key: \((publicKeyData.base64EncodedString()))") 
       //print("Public Key xor: \(publicKeyXor.base64EncodedString())") 
       publicKeyXor = self.publicKeyData! 

       let base: Int = 53 
       let length: Int = 40 
       let magic: Int = 95 

       for i in 0..<length{ 
        let index = i + base 
        publicKeyXor[index] = self.publicKeyData![magic]^self.publicKeyData![index] 
       } 
      } 


     return publicKeyXor 
    } 

    // decrypt 
    func decryptWithRSAKey(_ encryptedData: Data, padding: SecPadding = .PKCS1, rsaKeyRef: SecKey? = nil) -> Data? { 
     let rsaKeyRef = rsaKeyRef ?? self.privateKey! 
     let blockSize = SecKeyGetBlockSize(rsaKeyRef) 
     let dataSize = encryptedData.count/MemoryLayout<UInt8>.size 

     var encryptedDataAsArray = [UInt8](repeating: 0, count: dataSize) 
     (encryptedData as NSData).getBytes(&encryptedDataAsArray, length: dataSize) 

     var decryptedData = [UInt8](repeating: 0, count: 0) 
     var idx = 0 
     while (idx < encryptedDataAsArray.count) { 
      var idxEnd = idx + blockSize 
      if (idxEnd > encryptedDataAsArray.count) { 
       idxEnd = encryptedDataAsArray.count 
      } 
      var chunkData = [UInt8](repeating: 0, count: blockSize) 
      for i in idx..<idxEnd { 
       chunkData[i-idx] = encryptedDataAsArray[i] 
      } 

      var decryptedDataBuffer = [UInt8](repeating: 0, count: blockSize) 
      var decryptedDataLength = blockSize 

      let status = SecKeyDecrypt(rsaKeyRef, padding, chunkData, idxEnd-idx, &decryptedDataBuffer, &decryptedDataLength) 
      if (status != noErr) { 
       return nil 
      } 
      let finalData = removePadding(decryptedDataBuffer) 
      decryptedData += finalData 

      idx += blockSize 
     } 

     return Data(bytes: UnsafePointer<UInt8>(decryptedData), count: decryptedData.count) 
    } 

    // remove padding 
    func removePadding(_ data: [UInt8]) -> [UInt8] { 
     var idxFirstZero = -1 
     var idxNextZero = data.count 
     for i in 0..<data.count { 
      if (data[i] == 0) { 
       if (idxFirstZero < 0) { 
        idxFirstZero = i 
       } else { 
        idxNextZero = i 
        break 
       } 
      } 
     } 
     if (idxNextZero-idxFirstZero-1 == 0) { 
      idxNextZero = idxFirstZero 
      idxFirstZero = -1 
     } 
     var newData = [UInt8](repeating: 0, count: idxNextZero-idxFirstZero-1) 
     for i in idxFirstZero+1..<idxNextZero { 
      newData[i-idxFirstZero-1] = data[i] 
     } 
     return newData 
    } 

    // encrypt 
    func encryptWithRSAKey(_ data: Data, padding: SecPadding = .PKCS1, rsaKeyRef: SecKey? = nil) -> Data? { 
     let rsaKeyRef = rsaKeyRef ?? self.publicKey! 
     let blockSize = SecKeyGetBlockSize(rsaKeyRef) 
     let dataSize = data.count/MemoryLayout<UInt8>.size 
     let maxChunkSize = padding==SecPadding.OAEP ? (blockSize - 42) : (blockSize - 11) 

     var dataAsArray = [UInt8](repeating: 0, count: dataSize) 
     (data as NSData).getBytes(&dataAsArray, length: dataSize) 

     var encryptedData = [UInt8](repeating: 0, count: 0) 
     var idx = 0 
     while (idx < dataAsArray.count) { 
      var idxEnd = idx + maxChunkSize 
      if (idxEnd > dataAsArray.count) { 
       idxEnd = dataAsArray.count 
      } 
      var chunkData = [UInt8](repeating: 0, count: maxChunkSize) 
      for i in idx..<idxEnd { 
       chunkData[i-idx] = dataAsArray[i] 
      } 

      var encryptedDataBuffer = [UInt8](repeating: 0, count: blockSize) 
      var encryptedDataLength = blockSize 

      let status = SecKeyEncrypt(rsaKeyRef, padding, chunkData, idxEnd-idx, &encryptedDataBuffer, &encryptedDataLength) 
      if (status != noErr) { 
       NSLog("Error while encrypting: %i", status) 
       return nil 
      } 
      encryptedData += encryptedDataBuffer 

      idx += maxChunkSize 
     } 

     return Data(bytes: UnsafePointer<UInt8>(encryptedData), count: encryptedData.count) 
    } 

} 

保存該郵件到文件:

let message = "This is my message. asdfl;jas f;lkajsdf la;skfj asd;lkfj sa;dlkfjsad ;lkfj dsal;kfj daslk;fjds flkjas dfjkdfgjkhdfs gjklsdf lkgjhdfs klgj dfskljg fdslkjg dsfjklg dfskjlg dfskljg fdskljg fdskjlgn dfsjlknv sflkdjnv ldksfjnv dfsjnvdkfjsghlfsjkdgh fdskljgh dsfkljgh dfslkjghdljkfs sdfkljsadf dsaf;lkasdjf sad;lfjk as;ldkfjas d;flkjasd flk;asdf lkjha sdflhjka sdklgha fkljgh fsdkljg alkjfh aslkjdf asldkjfh asdljkfasdlkjfhas ldfh ash aslkj asdlkj aslkjchads lkjchadslkfjhsadlkfjhsad flkjasdh flkjashdf lkjadhsf lkjasdhf lkjashdf lkjasdhf lkadsjfhadslkfjhiuwlhoewiqufhopweif asjkbdsa kjfasdlkfja sdljkfhs alkjfh adsjkfhas ldfkjhas ldkfjhajlsfh alsjdfhadlsfhlasjdkfjhsad fljkls " 

     let encryptData: Data? = self.crypt.encryptWithRSAKey(message.data(using: .utf8)!) 

     let fileName = "file.enc" 
     let dir = try? FileManager.default.url(for: .documentDirectory, 
               in: .userDomainMask, appropriateFor: nil, create: false) 
if let fileURL = dir?.appendingPathComponent(fileName).appendingPathExtension("dgk") { 

      // Write to the file Test 
      do { 
       //    try encry.write(to: fileURL, atomically: true, encoding: .utf8) 
       try encryptData?.write(to: fileURL) 
      } catch { 
       print("Failed writing to URL: \(fileURL), Error: " + error.localizedDescription) 
      } 

     } 

,如果我在這個時候解密是成功的解密文件。但是當我關閉程序並打開它並解密文件時,解密方法失敗了。

if let fileURL = dir?.appendingPathComponent(fileName).appendingPathExtension("dgk") { 
      var encryptDataFromFile: Data? 
      do { 
       encryptDataFromFile = try Data(contentsOf: fileURL) 
       if let decryptData: Data = self.crypt.decryptWithRSAKey(encryptDataFromFile!){ 
        let decryptString: String = String(data: decryptData, encoding: .utf8)! 
        print(decryptString) 
       } 
       exit(0) 
      } catch { 
       print("Failed reading from URL: \(fileURL), Error: " + error.localizedDescription) 
      } 
     } 

Download XCode project

+1

什麼是文件大小以字節爲單位?請注意,RSA可以加密的數據大小小於密鑰大小。即使對於原始RSA,1024位密鑰也被限制爲小於128字節。通常,不對稱加密(如RSA)不用於加密數據,數據通常使用對稱加密(如AES)進行加密。 – zaph

+1

嘗試使用調試器隔離核心問題,並提供MWE。你已經分享了很多代碼來閱讀和記住。另外,什麼zaph說:你在做什麼是非常不規範的。這就是說,我注意到的一件事是:你爲什麼要自己去除填充物? – Raphael

+0

@zaph大小爲768字節。我對尺寸要小心,而對於填充,我是負11,並且使用塊限制。我的問題是:第一次當我保存加密郵件工作時,但當我註釋保存到文件部分,並從文件中讀取並解密時,解密不起作用。因爲從RSA加密的服務器數據,我必須使用它。 –

回答

1

更新

  1. 每次應用啓動它生成一個新的密鑰對,因此,先前加密的數據無法與新的不同的解密私鑰。密鑰(或至少私鑰)必須保存以供將來使用。

  2. 你錯誤地使用RSA加密塊!當數據量很大時,或者通常在加密數據時,採用hybrid encryption。這意味着創建一個隨機對稱密鑰,數據用對稱加密(AES)加密,對稱密鑰用非對稱加密(RSA)加密。這兩種加密是一起打包的。

  3. RSA可以加密的數據大小小於密鑰大小。即使對於原始RSA,1024位密鑰也被限制爲小於127字節。

    在代碼關鍵是1024個比特[kSecAttrKeySizeInBits] = 1024),其是128 字節。填充11個字節的可以加密的最大數據是116個字節。

  4. 真正的原因是爲什麼使用RSA(不對稱)與AES(對稱)密鑰加密?

    通常,不對稱加密(如RSA)不用於加密數據,數據通常使用對稱加密(如AES)進行加密。選擇通常歸結爲需要單獨的加密和解密密鑰和/或PKI。

    兩者在可比較的密鑰大小下都是安全的,AES速度更快。可比較的密鑰大小:AES 128位,RSA 3072位。見NIST: Recommendation for Key Management表2.

+0

我的代碼是第一次工作。請參閱gif(我添加它)並運行該項目並對其進行測試。非常感謝 –

+0

非常感謝。但我檢查它,我檢查了很多次鑰匙,鑰匙是一樣的,這就是重點! –

+0

如果您不在執行過程中保存密鑰,它們將會不同,並且解密將失敗,如您所見。另外,對於數據大於密鑰的情況,這種RSA的使用並不是可接受的解決方案,普遍接受的解決方案是使用對稱加密或者是單獨的加密和解密密鑰是需要的混合加密。 – zaph