2017-09-15 21 views
-2

Download XCode projectRSAの暗号化ファイルやテキスト

enter image description here

私はメッセージを暗号化してファイルに保存します。もし私がファイルを暗号化するときに同じ時刻にファイルを解読すると、解読は成功するが、それ以外の時に解読関数はnilを返す。

私はこのクラスを暗号化と復号化に使用します。

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を提供してください。読んで心に留めておくためにたくさんのコードを共有しています。また、ザフは言った:あなたがやっていることは、非常に非標準的です。それは、私が指摘していることの一つは、なぜパディングを自分で取り除くのですか? – Raphael

+0

@zaphサイズは768バイトです。私はサイズに注意しているし、パディングのためにマイナス11であり、制限のためにチャンクを使用する。私の問題は:暗号化メッセージの作業を保存するとき初めてですが、ファイルセクションに保存してファイルから読み込んで解読するだけで、解読は機能しません。 サーバからのデータがRSAで暗号化されているため、それを使用する必要があるためです。 –

答えて

1

更新

  1. アプリは、それが新しい鍵ペアを生成し、起動されるたびに、これ以前に暗号化されたデータは新しいと異なるで復号化することができません秘密鍵。キー(または少なくとも秘密鍵)は、将来の使用のために保存する必要があります。

  2. チャンクで暗号化してRSAを誤って使用しています。データサイズが大きい場合、または一般にデータを暗号化する場合は、hybrid encryptionが使用されます。つまり、ランダムな対称鍵が作成され、データは対称暗号化(AES)で暗号化され、対称鍵は非対称暗号化(RSA)で暗号化されます。 2つの暗号化は一緒にパッケージ化されています。

  3. RSAが暗号化できるデータサイズがキーサイズより小さい。未処理のRSAの場合でも、1024ビットのキーは127バイト未満に制限されています。

    コードでキー128 バイトビット[kSecAttrKeySizeInBits] = 1024)、です。暗号化できる最大のデータの11バイトのパディングは、116バイトです。

  4. 実際のところ、RSA(非対称)とAES(対称)キーの暗号化を使用するのはなぜですか?

    通常、RSAなどの非対称暗号化はデータの暗号化には使用されません。データは一般にAESなどの対称暗号化で暗号化されます。通常、選択は暗号化キーと復号化キーおよび/またはPKIを分離する必要があります。

    どちらも同等のキーサイズで安全であり、AESははるかに高速です。比較可能なキーサイズ:AES 128ビット、RSA 3072ビット。 NIST: Recommendation for Key Managementを参照してください。

+0

私のコードは初めての仕事です。 GIF(私はそれを追加します)を見て、プロジェクトを実行してテストしてください。ありがとうございます –

+0

ありがとうございます。しかし、私はそれをチェックし、私は何度もキー、同じキー、ポイントをチェックします! –

+0

実行の間にキーを保存しないと、キーの内容が異なり、解読が失敗することがあります。さらに、RSAのこの使用法は、鍵より大きいデータに対しては容認された解決策ではなく、一般的に受け入れられる解決法は、対称暗号化を使用することであるか、または別個の暗号化である。 – zaph