【问题标题】:Encrypt a String, save it to DB, load it and decrypt it加密字符串,将其保存到数据库,加载并解密
【发布时间】:2013-01-04 16:59:05
【问题描述】:

我必须将与另一个数据库的连接详细信息存储在数据库表中,我必须对这些数据库的密码进行加密,并且必须能够通过 SQL 脚本“手动”将数据插入该表...

我需要对其进行加密和解密,因为我的应用程序必须能够使用这些数据并连接到其他数据库,所以 MD5 和类似的没有用..

我想到了 Blowfish、AES 等...但是如果我将密码作为 VARCHAR 存储在数据库中,则解密部分不起作用...所以我将其存储为 BYTE,但如果我这样做了,没有人可以编写一个脚本来预加载表上的数据..

也许我在这里遗漏了一些东西......

这是我在将表中的注册表定义为 VARCHAR 时使用的代码:

package main;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;


public class Prueba {

    private static final String keyValue = "fd<[;.7e/OC0W!d|";
    private static final String ALG = "Blowfish";

    public static void main(String[] args) {
        String text = "some random text";

        try {
            SecretKeySpec key = new SecretKeySpec(keyValue.getBytes(), ALG);
            Cipher cipher = Cipher.getInstance(ALG);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] encryptedBytes = cipher.doFinal(text.getBytes());
            String encrypted = new String(encryptedBytes);

            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] recoveredBytes = cipher.doFinal(encrypted.getBytes());
            String recovered = new String(recoveredBytes);

        } catch (NoSuchAlgorithmException nsa) {
            nsa.printStackTrace();
        } catch (NoSuchPaddingException nspe) {
            nspe.printStackTrace();
        } catch (InvalidKeyException ike) {
            ike.printStackTrace();
        } catch (BadPaddingException bpe) {
            bpe.printStackTrace();
        } catch (IllegalBlockSizeException ibse) {
            ibse.printStackTrace();
        } 
    }


}

我得到了例外:

javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
    at com.sun.crypto.provider.SunJCE_h.b(DashoA12275)
    at com.sun.crypto.provider.SunJCE_h.b(DashoA12275)
    at com.sun.crypto.provider.BlowfishCipher.engineDoFinal(DashoA12275)
    at javax.crypto.Cipher.doFinal(DashoA12275)
    at main.Prueba.main(Prueba.java:30)

如果不是:

byte[] recoveredBytes = cipher.doFinal(encrypted.getBytes());

我愿意

byte[] recoveredBytes = cipher.doFinal(encryptedBytes);

我也不例外,但是我必须将密码存储为 byte[] 所以没有脚本可能......

有什么想法吗?

【问题讨论】:

  • 为什么不只存储字节的十六进制(或 Base64)编码字符串而不是字节本身?会有空间损失,但你可以从脚本等预加载。而且它可能在数据库之间更便携。
  • 我相信你会发现这很有用stackoverflow.com/a/4183913/579580
  • 出于安全原因,密码应始终存储为 byte[]
  • maerics 真是个好主意...我会问项目经理的...谢谢 :)

标签: java database encryption


【解决方案1】:

似乎当您将密钥存储为字节时,某处的某些东西会错误地解释它。可能是字符编码问题。

如果您想将密钥存储为文本,您可能需要先对其进行 base64 编码。然后,您可以将文本进行 base64 解码回密钥。

【讨论】:

  • 这在它到达数据库之前就注定了,这个问题源于encrypted.getBytes()encryptedBytes不同(这本身就是将字节数组转换为字符串引起的问题)
【解决方案2】:

最后,正如maerics所建议的,我这样解决了:

import org.apache.commons.net.util.Base64;

public class MyCrypto {

    /**
     * Codifica un texto usando Base64.
     * @param texto <code>String</code> texto a codificar.
     * @return <code>String</code> texto codificado.
     */
    public static String encrypt(String texto) {
        return new String(Base64.encodeBase64(texto.getBytes()));
    }

    /**
     * Decodifica un texto usando Base64.
     * @param texto <code>String</code> texto a decodificar.
     * @return <code>String</code> texto decodificado.
     */
    public static String decrypt(String texto) {
        return new String(Base64.decodeBase64(texto.getBytes()));
    }
}

【讨论】:

    【解决方案3】:
    String encrypted = new BASE64Encoder ().encodeBuffer ( encryptedBytes );            
    cipher.init(Cipher.DECRYPT_MODE, key);
    byte[] recoveredBytes = cipher.doFinal( new BASE64Decoder ().decodeBuffer (  encrypted ) );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-29
      • 1970-01-01
      • 2014-12-25
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 2016-03-15
      • 1970-01-01
      相关资源
      最近更新 更多