将密钥转换为字符串和反之亦然

时间:2011-03-18 17:09:38

标签: java string encryption

我正在生成一个密钥并需要将其存储在DB中,因此我将其转换为String,但要从String中获取密钥。有哪些可能的方法来实现这一目标?

我的代码是,

SecretKey key = KeyGenerator.getInstance("AES").generateKey();
String stringKey=key.toString();
System.out.println(stringKey);

如何从字符串中取回密钥?

7 个答案:

答案 0 :(得分:232)

您可以将SecretKey转换为字节数组(byte[]),然后将Base64编码为String。要转换回SecretKey,Base64会解码字符串并在SecretKeySpec中使用它来重建原始SecretKey

对于Java 8

SecretKey to String:

// create new key
SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
// get base64 encoded version of the key
String encodedKey = Base64.getEncoder().encodeToString(secretKey.getEncoded());

String to SecretKey:

// decode the base64 encoded string
byte[] decodedKey = Base64.getDecoder().decode(encodedKey);
// rebuild key using SecretKeySpec
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES"); 

对于Java 7及之前(包括Android):

注意I:您可以跳过Base64编码/解码部分,只需将byte[]存储在SQLite中。也就是说,执行Base64编码/解码并不是一项昂贵的操作,您几乎可以在任何数据库中存储字符串而不会出现问题。

注意II:早期的Java版本不包含java.langjava.util个软件包中的一个Base64。但是,可以使用Apache Commons CodecBouncy CastleGuava中的编解码器。

SecretKey to String:

// CREATE NEW KEY
// GET ENCODED VERSION OF KEY (THIS CAN BE STORED IN A DB)

    SecretKey secretKey;
    String stringKey;

    try {secretKey = KeyGenerator.getInstance("AES").generateKey();}
    catch (NoSuchAlgorithmException e) {/* LOG YOUR EXCEPTION */}

    if (secretKey != null) {stringKey = Base64.encodeToString(secretKey.getEncoded(), Base64.DEFAULT)}

String to SecretKey:

// DECODE YOUR BASE64 STRING
// REBUILD KEY USING SecretKeySpec

    byte[] encodedKey     = Base64.decode(stringKey, Base64.DEFAULT);
    SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");

答案 1 :(得分:4)

要显示创建一些快速失败的功能的乐趣,我已经编写了以下3个功能。

一个创建一个AES密钥,一个编码,一个解码。这三种方法可以与Java 8一起使用(不依赖于内部类或外部依赖项):

public static SecretKey generateAESKey(int keysize)
        throws InvalidParameterException {
    try {
        if (Cipher.getMaxAllowedKeyLength("AES") < keysize) {
            // this may be an issue if unlimited crypto is not installed
            throw new InvalidParameterException("Key size of " + keysize
                    + " not supported in this runtime");
        }

        final KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(keysize);
        return keyGen.generateKey();
    } catch (final NoSuchAlgorithmException e) {
        // AES functionality is a requirement for any Java SE runtime
        throw new IllegalStateException(
                "AES should always be present in a Java SE runtime", e);
    }
}

public static SecretKey decodeBase64ToAESKey(final String encodedKey)
        throws IllegalArgumentException {
    try {
        // throws IllegalArgumentException - if src is not in valid Base64
        // scheme
        final byte[] keyData = Base64.getDecoder().decode(encodedKey);
        final int keysize = keyData.length * Byte.SIZE;

        // this should be checked by a SecretKeyFactory, but that doesn't exist for AES
        switch (keysize) {
        case 128:
        case 192:
        case 256:
            break;
        default:
            throw new IllegalArgumentException("Invalid key size for AES: " + keysize);
        }

        if (Cipher.getMaxAllowedKeyLength("AES") < keysize) {
            // this may be an issue if unlimited crypto is not installed
            throw new IllegalArgumentException("Key size of " + keysize
                    + " not supported in this runtime");
        }

        // throws IllegalArgumentException - if key is empty
        final SecretKeySpec aesKey = new SecretKeySpec(keyData, "AES");
        return aesKey;
    } catch (final NoSuchAlgorithmException e) {
        // AES functionality is a requirement for any Java SE runtime
        throw new IllegalStateException(
                "AES should always be present in a Java SE runtime", e);
    }
}

public static String encodeAESKeyToBase64(final SecretKey aesKey)
        throws IllegalArgumentException {
    if (!aesKey.getAlgorithm().equalsIgnoreCase("AES")) {
        throw new IllegalArgumentException("Not an AES key");
    }

    final byte[] keyData = aesKey.getEncoded();
    final String encodedKey = Base64.getEncoder().encodeToString(keyData);
    return encodedKey;
}

答案 2 :(得分:2)

SecretKey 到字符串

我们将把 SecretKey 转换成一个字节数组。然后,我们将使用 Base64 编码将字节数组转换为 String

public static String convertSecretKeyToString(SecretKey secretKey) throws NoSuchAlgorithmException {
    byte[] rawData = secretKey.getEncoded();
    String encodedKey = Base64.getEncoder().encodeToString(rawData);
    return encodedKey;
}

字符串到 SecretKey

我们将使用 Base64 解码将编码的 String 键转换为字节数组。然后,使用SecretKeySpecs,我们将字节数组转换为SecretKey

public static SecretKey convertStringToSecretKeyto(String encodedKey) {
    byte[] decodedKey = Base64.getDecoder().decode(encodedKey);
    SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
    return originalKey;
}

答案 3 :(得分:1)

您不想使用.toString()

请注意,SecretKey继承自java.security.Key,它本身继承自Serializable。所以这里的关键(没有双关语)是将密钥序列化为ByteArrayOutputStream,获取byte []数组并将其存储到db中。反向过程是将byte []数组从db中取出,在byte []数组中创建一个ByteArrayInputStream,然后将SecretKey反序列化...

...甚至更简单,只需使用从java.security.Key(SecretKey的父接口)继承的.getEncoded()方法。此方法返回Key / SecretKey的编码byte []数组,您可以从数据库中存储或检索它。

这是假设您的SecretKey实现支持编码。否则,getEncoded()将返回null。

编辑:

您应该查看Key / SecretKey javadocs(可在Google页面的开头找到):

http://download.oracle.com/javase/6/docs/api/java/security/Key.html

或者来自CodeRanch(也可以使用相同的谷歌搜索找到):

http://www.coderanch.com/t/429127/java/java/Convertion-between-SecretKey-String-or

答案 4 :(得分:1)

实际上路易斯提出的并不适合我。我不得不想出另一种方式。这对我有所帮助。也可以帮到你。 链接:

  1. * .getEncoded():https://docs.oracle.com/javase/7/docs/api/java/security/Key.html

  2. 编码器信息:https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Encoder.html

  3. 解码器信息:https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Decoder.html

  4. 代码段: 对于编码:

    String temp = new String(Base64.getEncoder().encode(key.getEncoded()));
    

    用于解码:

    byte[] encodedKey = Base64.getDecoder().decode(temp);
    SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "DES");
    

答案 5 :(得分:0)

将SecretKeySpec转换为String,反之亦然: 您可以在getEncoded()中使用SecretKeySpec方法,byteArray可以使用encodeToString()string SecretKeySpec Base64 SecretKeySpec {1}}对象。

String转换为decode()时:在Base64中使用byteArraySecretKeySpec,您可以为此byteArray创建实例params为SecretKeySpec以重现String mAesKey_string; SecretKeySpec mAesKey= new SecretKeySpec(secretKey.getEncoded(), "AES"); //SecretKeySpec to String byte[] byteaes=mAesKey.getEncoded(); mAesKey_string=Base64.encodeToString(byteaes,Base64.NO_WRAP); //String to SecretKeySpec byte[] aesByte = Base64.decode(mAesKey_string, Base64.NO_WRAP); mAesKey= new SecretKeySpec(aesByte, "AES");

min_img = sitk.RegionalMinima(feature_img, backgroundValue=0, foregroundValue=1.0, fullyConnected=False, flatIsMinima=True)
marker_img = sitk.ConnectedComponent(min_img, fullyConnected=False)

答案 6 :(得分:-1)

尝试这个,它没有Base64(只包含在JDK 1.8中),这个代码也在以前的java版本中运行:)

private static String SK = "Secret Key in HEX";


//  To Encrupt

public static String encrypt( String Message ) throws Exception{

    byte[] KeyByte = hexStringToByteArray( SK);
    SecretKey k = new SecretKeySpec(KeyByte, 0, KeyByte.length, "DES");

    Cipher c = Cipher.getInstance("DES","SunJCE");
    c.init(1, k);
    byte mes_encrypted[] = cipher.doFinal(Message.getBytes());

    String MessageEncrypted = byteArrayToHexString(mes_encrypted);
    return MessageEncrypted;
}

//  To Decrypt

public static String decrypt( String MessageEncrypted )throws Exception{

    byte[] KeyByte = hexStringToByteArray( SK );
    SecretKey k = new SecretKeySpec(KeyByte, 0, KeyByte.length, "DES");

    Cipher dcr =  Cipher.getInstance("DES","SunJCE");
    dc.init(Cipher.DECRYPT_MODE, k);
    byte[] MesByte  = hexStringToByteArray( MessageEncrypted );
    byte mes_decrypted[] = dcipher.doFinal( MesByte );
    String MessageDecrypeted = new String(mes_decrypted);

    return MessageDecrypeted;
}

public static String byteArrayToHexString(byte bytes[]){

    StringBuffer hexDump = new StringBuffer();
    for(int i = 0; i < bytes.length; i++){
    if(bytes[i] < 0)
    {   
        hexDump.append(getDoubleHexValue(Integer.toHexString(256 - Math.abs(bytes[i]))).toUpperCase());
    }else
    {
        hexDump.append(getDoubleHexValue(Integer.toHexString(bytes[i])).toUpperCase());
    }
    return hexDump.toString();

}



public static byte[] hexStringToByteArray(String s) {

    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2)
    {   
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));
    }
    return data;

}