基于swift和java的RSA算法

基于swift和java的RSA算法,java,cryptography,rsa,public-key-encryption,Java,Cryptography,Rsa,Public Key Encryption,我需要在IOS设备上为RSA算法生成公钥/私钥,并使用加密文本将公钥发送到服务器。服务器必须读取公钥并解密用户消息 我有swift密码: func generateKeys(){ var publicKey: SecKey? var privateKey: SecKey? let publicKeyAttr: [NSObject: NSObject] = [kSecAttrIsPermanent:true as NSObject, kSecAttrApplicatio

我需要在IOS设备上为RSA算法生成公钥/私钥,并使用加密文本将公钥发送到服务器。服务器必须读取公钥并解密用户消息

我有swift密码:

 func generateKeys(){
    var publicKey: SecKey?
    var privateKey: SecKey?

    let publicKeyAttr: [NSObject: NSObject] = [kSecAttrIsPermanent:true as NSObject, kSecAttrApplicationTag:"publicTag".data(using: String.Encoding.utf8)! as NSObject]
    let privateKeyAttr: [NSObject: NSObject] = [kSecAttrIsPermanent:true as NSObject, kSecAttrApplicationTag:"privateTag".data(using: String.Encoding.utf8)! as NSObject]

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

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

    var error:Unmanaged<CFError>?
    if #available(iOS 10.0, *) {
        if let cfdata = SecKeyCopyExternalRepresentation(publicKey!, &error) {
            let data:Data = cfdata as Data
            let b64Key = data.base64EncodedString(options: .lineLength64Characters)
            print("public base 64 : \n\(b64Key)")
        }
        if let cfdata = SecKeyCopyExternalRepresentation(privateKey!, &error) {
            let data:Data = cfdata as Data
            let b64Key = data.base64EncodedString(options: .lineLength64Characters)
            print("private base 64 : \n\(b64Key)")
        }
    }
    let encrypted = encryptBase64(text: "test", key: publicKey!)
    let decrypted = decpryptBase64(encrpted: encrypted, key: privateKey!)

    print("decrypted \(String(describing: decrypted))")

    self.dismiss(animated: true, completion: nil);
}


func encryptBase64(text: String, key: SecKey) -> String {
    let plainBuffer = [UInt8](text.utf8)
    var cipherBufferSize : Int = Int(SecKeyGetBlockSize(key))
    var cipherBuffer = [UInt8](repeating:0, count:Int(cipherBufferSize))

    // Encrypto  should less than key length
    let status = SecKeyEncrypt(key, SecPadding.PKCS1, plainBuffer, plainBuffer.count, &cipherBuffer, &cipherBufferSize)
    if (status != errSecSuccess) {
        print("Failed Encryption")
    }

    let mudata = NSData(bytes: &cipherBuffer, length: cipherBufferSize)
    return mudata.base64EncodedString()
}

func decpryptBase64(encrpted: String, key: SecKey) -> String? {
    let data : NSData = NSData(base64Encoded: encrpted, options: .ignoreUnknownCharacters)!
    let count = data.length / MemoryLayout<UInt8>.size
    var array = [UInt8](repeating: 0, count: count)
    data.getBytes(&array, length:count * MemoryLayout<UInt8>.size)

    var plaintextBufferSize = Int(SecKeyGetBlockSize(key))
    var plaintextBuffer = [UInt8](repeating:0, count:Int(plaintextBufferSize))

    let status = SecKeyDecrypt(key, SecPadding.PKCS1, array, plaintextBufferSize, &plaintextBuffer, &plaintextBufferSize)

    if (status != errSecSuccess) {
        print("Failed Decrypt")
        return nil
    }
    return NSString(bytes: &plaintextBuffer, length: plaintextBufferSize, encoding: String.Encoding.utf8.rawValue)! as String
}
但我无法解密用户消息。你能帮我解密信息吗?我编写了小单元测试

import org.junit.Test;

import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

import static org.junit.Assert.assertNotNull;

public class TestExample {
    String publicKeyContent = "MIMAAiMwDQYJKoZIhvcNAQEBBQADgwACDwAwggIKAoICAQC4K4zr1jTi4SSypXbrNeGd2HbYlrDRIPsPcL5a4JwGUKXwi+Rpf8Xh0D4dcRRH+Rtd5F66aqdGnhCBKtU5XsmlT+QssIggihI0iF3LEPsMlKapDrDdSbWmuitVDSSlulReMcN3hEUl8AzlNyu817snZtYESiFxm87QV6xZAcrWzvIdyiStBbngCT/v76tOZDX56IIRGoLMi3WND7538PqqYheh2+oZk05O+Bf5LZc6YteTRLLOSyIIxesoABo8tvaFyIo2ihMcnDRnGAzOMNTLXiQdj2scAMCVr3oiLpU48+Iw8ptOUBDQioW15FsYd3ugZhUX+/mFtMFsYkJyYjyG5HCqAs2/wm6eIjjy1QQwUF2hB8Z7sqyF5KrVZOv6Q7+pB83tT02ZXcDXCdsiP10G3sA4kjc/r9TuQHjCIwZa1LO4tPaO8qAzlROHIkQ4FhdaAM9U9DUq3nBywQLcEVQmXeH1OA1ve96QbMQoN+SRPh0Kq6W0U4TbzvMskQ7bePKDjiWP2fdtgSfrnOsyJaLi04n+hDsgiMfd4N9tauSMpCY6H9l7yYPc5Z+3qG2ANhteZGa7wT1OZoGLkZV0OurnA4xkzwcB7h0RVEvABB9dtl6S60FK1NELQy6sC/HCcivo9sJ+C1g2Sln+8qEdiju86X5ja5pGiRhJAxwSp2ZKgwIDAQAB";
    String encryptedMessage = "g81SOC9XOD9zq5qfyhkdP/7ronNb82g3ueDtEh711L43zPSgrFksLEdIud/1fiDcV6N97RD41vb/iXtCg2/Gu6XliEhCaoG28reetG1cBndKF9UzQw9cYChp54S1wnhBkAAZQ4Of3c77DtPBCL4gcgv2ilBTm7o+NR2wXunfJ7Olbbau+7C1pa+Qv/+sz45r4gJmQ1MfGjHtw9e/U/3vjL9BfCEPn9Mo2zAZhkI81S0Ewth+csHwb3YTlE8mtHni1fvLRVXjvHk+57U3keoYPZk+93ytFL6pqkWMk+9VbLuUFHXn1mpSMiEr9GRN6XKRvEbbPp5lI9WjwRvtWfmRm5gLY76QinTrPb0KJg7oWmEoQie5o9W6MOkD+8vYV/SkkLT855SB3O57QLKCZmlSPlccE6GWfglHhAwRwrcTDY1bO/xH38gvYYPaAJMtJKtOVrqGxNkIUPwCCkdBa9JQwDSyTYxeh8AxC0ACs9cYVjMPrmC9zIZuRbmcneIGSugtzMZmI9qbLtW1aMlWuGrVyVhJlcCZuTJXWyBgx8xj8coX9YwUXSi1A4dL/Hl5Sme+HhAQs7OcH6ZZpsPmIIozXxHgOMhUo8k++cWg6+pudSoB2tr4NhxX/ID2jd1ELsg1C6mbxaKaGgXwfU9w4ZngbRxGTBlKWXwUP/xBa5BARZ4=";

    @Test
    public void encryptTest() throws Exception {
        PublicKey publicKey = convertPublicKey(publicKeyContent);
        assertNotNull(publicKey);

        String s = decryptString(publicKey, encryptedMessage);
        assertNotNull(s);
    }

    private PublicKey convertPublicKey(String publicKey) throws RSAAlgorithmException {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            //generate public key
            byte[] publicBytes = Base64.getDecoder().decode(publicKey);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
            return keyFactory.generatePublic(keySpec);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw new RSAAlgorithmException("Unable to generate public key from string " + publicKey + " . " + e.getMessage());
        }
    }

    private String decryptString(PublicKey publicKey, String value) throws Exception {
        byte[] decodedBytes;
        try {
            Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            c.init(Cipher.DECRYPT_MODE, publicKey);
            decodedBytes = c.doFinal(value.getBytes());
        } catch (Exception e) {
            System.out.println("Error = " + e);
            throw new Exception(e);
        }
        return new String(decodedBytes);
    }
}
我有下一个错误:

java.lang.Exception: javax.crypto.IllegalBlockSizeException: Data must not be longer than 512 bytes

在非对称密码系统中,您有一个由公钥和私钥组成的密钥对

用公钥加密,用私钥解密。公钥可以与其他方共享(公开),使他们能够向您发送加密消息。私钥是保密的,因此只有您可以解密使用公钥加密的消息

通常不使用RSA直接加密消息,因为消息必须短于模数,并且可能会带来安全隐患。取而代之的是,您为对称加密方案生成一个随机密钥,例如AES-256-CTR(或AES-256-GCM,如果您除了需要保密外还需要身份验证),使用对称加密方案加密消息,使用非对称加密方案加密对称密码的密钥,并发送(非对称)两个密钥加密密钥和(对称)加密消息发送给接收方

接收方将首先使用其私钥解密对称加密方案的密钥,然后使用该密钥解密实际消息。这有时被称为“混合加密”,它使消息(或多或少)任意长

所以,你要做的是以下几点

  • 您必须为加密消息的接收者生成密钥对。因此,如果您的通信是单向的(iOS设备向服务器发送数据,但没有数据返回),则只需要为服务器生成密钥对。如果服务器需要回话,那么还需要为客户端生成密钥对

  • 为了向服务器发送加密消息,客户端需要具有服务器的公钥。因此,你必须设法把它转移到那里。问题是,此传输需要安全,否则攻击者可能会模拟服务器,向您提供他/她的公钥(他/她知道私钥对应方),拦截所有流量,用他/她的私钥解密,用服务器的公钥重新加密,并将其传递给服务器。这被称为<强>中间人攻击< /强>,并允许攻击者拦截和(可能操纵)所有服务器和服务器之间的通信。因此,您的最佳选择可能根本不是交换公钥,而是将公钥嵌入到应用程序中。这将阻止人在中间的攻击,只要应用程序代码可以被认证的方法共享。

  • 当您想向服务器发送消息时,生成一个随机对称加密密钥(使用加密安全的随机数生成器-这是而不是您语言的默认“随机”函数),用它和适当的对称加密方案加密消息,您可以根据自己的要求选择(例如,需要认证?然后使用AES-GCM-只需要保密?然后使用AES-CTR)。大多数加密方案还需要随机(不可预测)初始化向量,您也可以使用CSPRNG生成该向量,并且必须将其发送到接收器,因为解密需要该向量,但无需保密

  • 使用非对称加密方案和服务器的公钥加密对称加密方案的密钥。RSA-PKCS1已“注明日期”。我会尝试使用RSA-OAEP,因为它具有更理想的安全属性。将加密密钥发送到服务器

  • 服务器使用非对称加密方案和他的私钥(保持机密)解密对称加密方案的密钥。然后使用对称加密方案对消息进行解密

  • 由于这其中大部分都很复杂,许多细微的细节可能导致安全漏洞,因此我建议您自己执行而不是。我建议您只使用TLS(可能带有一个受限的参数集)并实现您自己的证书验证器,将服务器的公钥与已知的良好值进行比较,以消除整个PKI内容,这需要花钱,而且从一开始就不是很安全。至少,我会这样做

    或者,如果您想推出自己的“专有”协议,您可以尝试使用一个更“开发人员友好”的加密库,尤其是NaCl。这将抽象掉许多“血淋淋的细节”,并为您选择许多正常的默认值,这些默认值无法被覆盖,所有这些都使得实现不安全的协议变得更加困难


    记住,这不是说你“太笨了”。这是做这些事情的正确方法。说到加密,DIY越少越好。你使用的加密技术越广泛,审查的次数越多,缺陷修复的速度也越快,因此使用像NaCl这样的东西,在成千上万的应用程序中使用,是相当不错的。只要其他应用程序是安全的,您的应用程序(可能)也是安全的。当发现漏洞时,NaCl将得到更新,您只需更新应用程序中的库,并且自动安全,因此您(几乎)不需要进行内部审查和修补,并且您的漏洞窗口(通常)很短。

    首先尝试创建对称实现。仅仅显示三行而没有任何调试或错误指示基本上是要求我们做你的w
    java.lang.Exception: javax.crypto.IllegalBlockSizeException: Data must not be longer than 512 bytes