这是使用java加密(使用公私钥)可能通过不安全网络发送的消息的安全方法吗?



我不是这方面的专家,所以我需要听从专家的意见。下面的示例是加密和解密消息(长度未知)的合理安全方法,以便在可能不安全的网络(即电子邮件、HTTP请求或其他方式)上传输。我所说的"相当安全"是指,可以防止一个偶然的或半确定的第三方读取消息。

使用随机AES密钥加密消息,并通过公钥加密来保护AES密钥。

public static String encrypt(String data, PublicKey publicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
    // Create AES secret key
    Cipher aes = Cipher.getInstance("AES");
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    kgen.init(256);
    SecretKey key = kgen.generateKey();
    SecretKeySpec aeskeySpec = new SecretKeySpec(key.getEncoded(), "AES");
    // Encrypt data with AES Secret key
    aes.init(Cipher.ENCRYPT_MODE, aeskeySpec);
    byte[] dataEncoded = aes.doFinal(data.getBytes());
    // Encrypt the secret AES key with the public key
    Cipher rsa = Cipher.getInstance("RSA");
    rsa.init(Cipher.ENCRYPT_MODE, publicKey);
    byte[] aesKeyEncoded = rsa.doFinal(key.getEncoded());
    // Output both secret AES key and data
    return
        Base64.getEncoder().encodeToString(aesKeyEncoded) + "~" +
        Base64.getEncoder().encodeToString(dataEncoded);
}

解密AES密钥,然后解密消息:

public static String decrypt(String data, PrivateKey privateKey) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException {
    String[] parts = data.split("~");
    // Decrypt AES secret key
    byte[] encodedSecretKey = Base64.getDecoder().decode(parts[0]);
    Cipher rsa = Cipher.getInstance("RSA");
    rsa.init(Cipher.DECRYPT_MODE, privateKey);
    byte[] decodedSecretKey = rsa.doFinal(encodedSecretKey);
    SecretKeySpec key = new SecretKeySpec(decodedSecretKey, "AES");
    // Decrypt message
    Cipher aes = Cipher.getInstance("AES");
    aes.init(Cipher.DECRYPT_MODE, key);
    byte[] decodedData = aes.doFinal(Base64.getDecoder().decode(parts[1]));
    return new String(decodedData);
}

使用上述方法:

public static void main(String args[]) throws NoSuchAlgorithmException, BadPaddingException, NoSuchPaddingException, IllegalBlockSizeException, InvalidKeyException {
    // Generate public/private key
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
    generator.initialize(2048, new SecureRandom());
    KeyPair kp = generator.generateKeyPair();
    System.out.println(" Public key = " + Base64.getEncoder().encodeToString(kp.getPublic().getEncoded()));
    System.out.println("Private key = " + Base64.getEncoder().encodeToString(kp.getPrivate().getEncoded()));
    String mytext = "test message with some test data.";
    String e = encrypt(mytext, kp.getPublic());
    String d = decrypt(e, kp.getPrivate());
    System.out.println("        text = " + mytext);
    System.out.println("Decoded text = " + d);
}

只要您可以信任RSA公钥,总体思路就没问题。如果您只是将公钥发送给另一方,那么它就不是。

您还需要通过添加完整性和真实性来保护您的密文。您可以通过切换到AES/GCM模式(仅在Java 8中可用,或者使用Bouncy Castle)轻松地做到这一点。当前您正在使用不安全的AES/ECB加密模式。

您应该尝试使用带有OAEP填充的RSA,而不是pkcs# 1 v1.5填充。一般来说,您不应该依赖默认的字符编码(getBytes())或密码模式。

所以最后:不,那不安全。如果您想避免许多陷阱,请尝试使用TLS。

相关内容

最新更新