美文网首页
iOS RSA 加密算法,非对称加密,适用小数据

iOS RSA 加密算法,非对称加密,适用小数据

作者: 移动的键盘 | 来源:发表于2020-11-27 18:33 被阅读0次

    /// 支持的RSA keySize 大小有:512,768,1024,2048位
    /// 支持的RSA 填充方式有三种:NOPadding,PKCS1,OAEP 三种方式 ,填充方式影响最大分组加密数据块的大小
    /// 签名使用的填充方式PKCS1, 支持的签名算法有 sha1,sha256,sha224,sha384,sha512
    /// Nopadding填充最大数据块为 接口 SecKeyGetBlockSize 大小;
    /// PKCS1 填充方式最大数据为 SecKeyGetBlockSize大小 减去11
    /// OAEP 填充方式最大数据为 SecKeyGetBlockSize 大小减去 42
    /// RSA加密解密签名,适合小块的数据处理,大量数量需要处理分组逻辑;密码学中推荐使用对称加密进行数据加密,使用RSA来加密对称密钥

    生成密钥对

    /**
    #!/usr/bin/env bash
    echo "Generating RSA key pair ..."
    echo "1024 RSA key: private_key.pem"
    openssl genrsa -out private_key.pem 1024
    
    echo "create certification require file: rsaCertReq.csr"
    openssl req -new -key private_key.pem -out rsaCertReq.csr
    
    echo "create certification using x509: rsaCert.crt"
    openssl x509 -req -days 3650 -in rsaCertReq.csr -signkey private_key.pem -out rsaCert.crt
    
    echo "create public_key.der For IOS"
    openssl x509 -outform der -in rsaCert.crt -out public_key.der
    
    echo "create private_key.p12 For IOS. Please remember your password. The password will be used in iOS."
    openssl pkcs12 -export -out private_key.p12 -inkey private_key.pem -in rsaCert.crt
    
    echo "create rsa_public_key.pem For Java"
    openssl rsa -in private_key.pem -out rsa_public_key.pem -pubout
    echo "create pkcs8_private_key.pem For Java"
    openssl pkcs8 -topk8 -in private_key.pem -out pkcs8_private_key.pem -nocrypt
    
    echo "finished."
    ********************************************************************************/
    

    加密算法

    import UIKit
    import Security
    
    public class ShgRSASwift: NSObject {
    
    /// RSA 加密,公钥加密
    /// - Parameters:
    ///   - aString: 需要加密的字符串
    ///   - publicKeyPath: 公钥文件路径
    /// - Returns: 加密后的字符串
    @objc public class func encrypt(_ aString:String,_ publicKeyPath:String) -> String? {
        
        if aString.count == 0 || publicKeyPath.count == 0 {
            return nil
        }
        
        guard let secKey:SecKey = self.publicSecKey(publicKeyPath) else {
            return nil
        }
        
        guard let data:Data = aString.data(using: .utf8) else {
            return nil
        }
        
        //输入数据bytes
        let dataByte = [UInt8](data)
        
        //输入数据长度
        let dataLenght = data.count
    
        //公钥块长度
        let secKeyBlockSize = SecKeyGetBlockSize(secKey)
        
        //输出buffer
        let output = UnsafeMutablePointer<UInt8>.allocate(capacity: secKeyBlockSize)
        
        //说明:如果填充模式为 PKCS1 ,可加密数据块最大长度为 SecKeyGetBlockSize() - 11
        let maxInputLenght = secKeyBlockSize - 11
    
        var status:OSStatus = noErr
        
        var outLength:Int = secKeyBlockSize
        
        //RSA加密块数据长度不能大于密钥块长度,当数据大于密钥块长度时,进行分组加密
        if dataLenght > maxInputLenght {
            
            let index:Int = Int(ceilf(Float(dataLenght)/Float(maxInputLenght)))
            
            var rsaStr:String = ""
            
            for i:Int in 0 ..< index {
                
                let sufLength = dataLenght - i * maxInputLenght
                
                guard let range:Range = Range.init(NSMakeRange(i * maxInputLenght, i == index - 1 ? sufLength : maxInputLenght)) else {
                    return nil
                }
                
                let subData:Data = data.subdata(in: range)
                
                let subByte = [UInt8](subData)
                
                status = SecKeyEncrypt(secKey, SecPadding.PKCS1, subByte, maxInputLenght, output, &outLength)
                
                if status != noErr {
                    return nil
                }
                
                for i:Int in 0 ..< outLength {
                    rsaStr = rsaStr.appendingFormat("%02x", _:output[i])
                }
            }
            
            output.deallocate()
            
            return rsaStr
            
        } else {
            
            status = SecKeyEncrypt(secKey, SecPadding.PKCS1, dataByte, dataLenght, output, &outLength)
            
            if status != noErr {
                return nil
            }
            
            var rsaStr:String = ""
            
            for i:Int in 0 ..< outLength {
                rsaStr = rsaStr.appendingFormat("%02x", _:output[i])
            }
            
            output.deallocate()
            
            return rsaStr
        }
    }
    
    /// 获取公钥 .der证书
    /// - Parameter publicKeyPath: 公钥文件路径
    /// - Returns: 公钥
    class func publicSecKey(_ publicKeyPath:String) -> SecKey? {
        
        let url:URL = URL.init(fileURLWithPath: publicKeyPath)
        
        var data:Data
        
        do {
            try data = Data.init(contentsOf: url)
        } catch  {
            return nil
        }
        
        let dataByte = [UInt8](data)
        
        let cfData:CFData = CFDataCreate(kCFAllocatorDefault, dataByte, CFIndex(dataByte.count))
        
        guard let cert:SecCertificate = SecCertificateCreateWithData(nil, cfData) else {
            return nil
        }
        
        var trust:SecTrust?
        
        let policy:SecPolicy = SecPolicyCreateBasicX509()
      
        let status:OSStatus = SecTrustCreateWithCertificates(cert, policy, &trust)
        
        if status != noErr {
            return nil
        }
        
        var result:SecTrustResultType = .invalid
        
        if SecTrustEvaluate(trust!, &result) != noErr {
            return nil
        }
        
        guard let secKey:SecKey = SecTrustCopyPublicKey(trust!) else {
            return nil
        }
        
        return secKey
    }
    }
    
    /// RSA 解密,私钥解密
    /// - Parameters:
    ///   - data: 需要解密的data
    ///   - privateKeyPath: 私钥文件路径
    /// - Returns: 解密后的字符串
    @objc public class func decrypt(_ data:Data,_ privateKeyPath:String) -> String? {
        
        if data.count == 0 || privateKeyPath.count == 0 {
            return nil
        }
        
        guard let secKey:SecKey = self.privateSecKey(privateKeyPath) else {
            return nil
        }
        
        //输入数据bytes
        let dataByte = [UInt8](data)
        
        //输入数据长度
        let dataLenght = data.count
    
        //私钥块长度
        let secKeyBlockSize = SecKeyGetBlockSize(secKey)
        
        //输出buffer
        let output = UnsafeMutablePointer<UInt8>.allocate(capacity: secKeyBlockSize)
        
        let maxInputLenght = secKeyBlockSize
    
        var status:OSStatus = noErr
        
        var outLength:Int = secKeyBlockSize
        
        //RSA解密块数据长度不能大于密钥块长度,当数据大于密钥块长度时,进行分组解密
        if dataLenght > maxInputLenght {
            
            let index:Int = Int(ceilf(Float(dataLenght)/Float(maxInputLenght)))
            
            var outData:Data = Data()
         
            for i:Int in 0 ..< index {
                
                let sufLength = dataLenght - i * maxInputLenght
                
                guard let range:Range = Range.init(NSMakeRange(i * maxInputLenght, i == index - 1 ? sufLength : maxInputLenght)) else {
                    return nil
                }
                
                let subData:Data = data.subdata(in: range)
                
                let subByte = [UInt8](subData)
                
                status = SecKeyDecrypt(secKey, SecPadding.init(rawValue: 0), subByte, subData.count, output, &outLength)
                
                if status != noErr {
                    return nil
                }
                
                var idxFirstZero:Int = -1
                
                var idxNextZero:Int = outLength
                
                for i:Int in 0 ..< outLength {
                    if output[i] == 0 {
                        if idxFirstZero < 0 {
                            idxFirstZero = i
                        } else {
                            idxNextZero = i
                            break
                        }
                    }
                }
                
                outData.append(&output[idxFirstZero + 1], count: idxNextZero - idxFirstZero - 1)
                
            }
            
            output.deallocate()
            
            let rsaStr:String? = String.init(data: outData, encoding: .utf8)
            
            return rsaStr
            
        } else {
            
            status = SecKeyDecrypt(secKey, SecPadding.PKCS1, dataByte, dataLenght, output, &outLength)
            
            if status != noErr {
                return nil
            }
            
            var idxFirstZero:Int = -1
            
            var idxNextZero:Int = outLength
            
            for i:Int in 0 ..< outLength {
                if output[i] == 0 {
                    if idxFirstZero < 0 {
                        idxFirstZero = i
                    } else {
                        idxNextZero = i
                        break
                    }
                }
            }
            
            var outData:Data = Data()
            
            outData.append(&output[idxFirstZero + 1], count: idxNextZero - idxFirstZero - 1)
            
            output.deallocate()
            
            let rsaStr:String? = String.init(data: outData, encoding: .utf8)
            
            return rsaStr
        }
    }
    
    /// 获取私钥 .p12证书
    /// - Parameter privateKeyPath: 私钥文件路径
    /// - Returns: 私钥
    class func privateSecKey(_ privateKeyPath:String) -> SecKey? {
        
        let url:URL = URL.init(fileURLWithPath: privateKeyPath)
        
        var data:CFData
        
        do {
            try data = Data.init(contentsOf: url) as CFData
        } catch  {
            return nil
        }
        
        let options:CFMutableDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, CFIndex(0), nil, nil)
        
        // 对象转 UnsafeRawPointer
        let key = Unmanaged.passRetained(kSecImportExportPassphrase as NSString).autorelease().toOpaque()
        
        let value = Unmanaged.passRetained("1" as NSString).autorelease().toOpaque()
        
        CFDictionaryAddValue(options, key, value)
        
        var items:CFArray? = CFArrayCreate(nil, UnsafeMutablePointer<UnsafeRawPointer?>(bitPattern: 0), 0, nil)
        
        let securityError:OSStatus = SecPKCS12Import(data, options, &items)
        
        if securityError == noErr && CFArrayGetCount(items) > 0 {
            
            let identityDict = CFArrayGetValueAtIndex(items, 0)
            
            // UnsafeRawPointer 转 任意类型
            let cfDic:CFDictionary = Unmanaged.fromOpaque(identityDict!).takeUnretainedValue()
            
            if CFDictionaryGetCount(cfDic) == 0 {
                return nil
            }
            
            let identityKey = Unmanaged.passRetained(kSecImportItemIdentity as NSString).autorelease().toOpaque()
            
            let identityPriv = CFDictionaryGetValue(cfDic, identityKey)
            
            let identity:SecIdentity = Unmanaged.fromOpaque(identityPriv!).takeUnretainedValue()
            
            var secKey:SecKey?
            
            let status = SecIdentityCopyPrivateKey(identity, &secKey)
            
            if status == noErr {
                return secKey
            }
        }
        
        return nil
    }

    相关文章

      网友评论

          本文标题:iOS RSA 加密算法,非对称加密,适用小数据

          本文链接:https://www.haomeiwen.com/subject/doxfwktx.html