RSA加密文件或文本

时间:2017-09-15 14:32:34

标签: swift rsa

Download XCode project

enter image description here

我加密邮件并将其保存到文件中。如果我在加密文件的同时解密文件,解密成功但是如果其他时间解密函数返回nil。

我使用此类进行加密和解密。

max = max(max,indexPath.row)

将此消息保存到文件:

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)
            }

        }

Download XCode project

1 个答案:

答案 0 :(得分:1)

<强>更新

  1. 每次启动应用程序时,它都会生成一个新的密钥对,因此无法使用新的和不同的私钥解密以前加密的数据。必须保存密钥(或至少私钥)以备将来使用。

  2. 您通过加密块来误用RSA!当数据大小很大时,或者通常加密数据时,使用hybrid encryption。这意味着创建随机对称密钥,使用对称加密(AES)对数据进行加密,并使用非对称加密(RSA)对对称密钥进行加密。这两种加密打包在一起。

  3. RSA可以加密的数据大小小于密钥大小。即使对于原始RSA,1024位密钥也限制为小于127个字节。

    在密码中,密钥为1024 [kSecAttrKeySizeInBits] = 1024),即128 bytes 。考虑到11个字节的填充,可以加密的最大数据是116个字节。

  4. 真正的问题是为什么要使用RSA(非对称)和AES(对称)密钥加密?

    通常,RSA等非对称加密不用于加密数据,数据通常使用AES等对称加密进行加密。选择通常归结为需要单独的加密和解密密钥和/或PKI。

    两者在可比较的密钥大小上都是安全的,AES更快。可比密钥大小:AES 128位,RSA 3072位。见NIST: Recommendation for Key Management表2。