首页 > 解决方案 > 安全传输 SecretKey 以对密码进行加密/解密

问题描述

我正在考虑使用 ChaCha20-Poly1305 加密/解密密码(我需要加密/解密不能只散列)。但是,要使用此算法,我们需要使用密钥。但是,这是一个问题,因为我在他们的设备上加密/解密用户的密码,所以在我的数据库中我只存储他们的加密密码。

问题在于,如果用户从他们的手机中卸载我的应用程序或更换为新手机,我将需要相同的密钥才能再次解密用户的密码。

我的问题是:我如何安全地传输和存储这个密钥?

另外,如果您对我的问题有更好的替代方案,例如不同的加密算法或方法,请告诉我。

这是我提到的 SecretKey 对象的代码示例:

package com.javainterviewpoint;

import java.security.spec.AlgorithmParameterSpec;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class ChaCha20Poly1305Example
{
    static String plainText = "This is a plain text which will be encrypted by ChaCha20 Poly1305 Algorithm";

    public static void main(String[] args) throws Exception
    {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("ChaCha20");
        keyGenerator.init(256);

        // Generate Key
        SecretKey key = keyGenerator.generateKey();

        System.out.println("Original Text  : " + plainText);

        byte[] cipherText = encrypt(plainText.getBytes(), key);
        System.out.println("Encrypted Text : " + Base64.getEncoder().encodeToString(cipherText));

        String decryptedText = decrypt(cipherText, key);
        System.out.println("DeCrypted Text : " + decryptedText);

    }

    public static byte[] encrypt(byte[] plaintext, SecretKey key) throws Exception
    {
        byte[] nonceBytes = new byte[12];

        // Get Cipher Instance
        Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305/None/NoPadding");
        
        // Create IvParamterSpec
        AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(nonceBytes);

        // Create SecretKeySpec
        SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "ChaCha20");

        // Initialize Cipher for ENCRYPT_MODE
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec);

        // Perform Encryption
        byte[] cipherText = cipher.doFinal(plaintext);

        return cipherText;
    }

    public static String decrypt(byte[] cipherText, SecretKey key) throws Exception
    {
        byte[] nonceBytes = new byte[12];

        // Get Cipher Instance
        Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305/None/NoPadding");

        // Create IvParamterSpec
        AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(nonceBytes);
                
        // Create SecretKeySpec
        SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "ChaCha20");

        // Initialize Cipher for DECRYPT_MODE
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);

        // Perform Decryption
        byte[] decryptedText = cipher.doFinal(cipherText);

        return new String(decryptedText);
    }
}

标签: javaencryptioncryptographypassword-encryptionsecret-key

解决方案


对于对称加密和解密,最佳实践是使用一个 MASTER KEY,它是固定字符串或具有固定算法,您知道如何生成它。您必须使用此 MASTER KEY 来加密和解密所有其他密钥(名称 WORKING KEYS)来加密/解密真实数据。

如果您的设备有一个安全区域,您可以安全地保存您的密钥,您必须通过另一台设备或通过与服务器通信在其上注入主密钥。如果没有,您将面临泄露密钥的风险。

但是,如果您是应用程序的唯一程序员,您可以使用固定算法生成 MASTER 密钥。例如使用设备hash(xor(1c1c1cID。现在,设备可以向服务器发送获取工作密钥的请求(通过发送其 id 和由主密钥加密的 mac-block),然后您返回正确的工作密钥。

此方案在 ISO-8583 支付中使用。


推荐阅读