将字符串转换为加密密钥,反之亦然java

Posted

技术标签:

【中文标题】将字符串转换为加密密钥,反之亦然java【英文标题】:Converting Strings to encryption keys and vice versa java 【发布时间】:2012-04-03 01:06:39 【问题描述】:

我目前正在研究一种将键转换为字符串的方法,反之亦然。它适用于公钥转换,并将私钥转换为字符串。出于某种原因,相同的代码不会将字符串转换回私钥,我只是无法弄清楚。

转换器代码为:

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

@SuppressWarnings("restriction")
public  class KeyConvert 


public static PublicKey stringToPublicKey(String s) 

    BASE64Decoder decoder = new BASE64Decoder();

    byte[] c = null;
    KeyFactory keyFact = null;
    PublicKey returnKey = null;

    try 
        c = decoder.decodeBuffer(s);
        keyFact = KeyFactory.getInstance("DSA", "SUN");
     catch (Exception e) 
        System.out.println("Error in Keygen");
        e.printStackTrace();
    


    X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(c);
    try 
        returnKey = keyFact.generatePublic(x509KeySpec);
     catch (Exception e) 

        System.out.println("Error in Keygen2");
        e.printStackTrace();

    

    return returnKey; 


public static PrivateKey stringToPrivateKey(String s) 

    BASE64Decoder decoder = new BASE64Decoder();
    byte[] c = null;
    KeyFactory keyFact = null;
    PrivateKey returnKey = null;

    try 

                    c = decoder.decodeBuffer(s);
        keyFact = KeyFactory.getInstance("DSA", "SUN");
     catch (Exception e) 

        System.out.println("Error in first try catch of stringToPrivateKey");
        e.printStackTrace();
    


    X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(c);
    try    //the next line causes the crash
        returnKey = keyFact.generatePrivate(x509KeySpec);
     catch (Exception e) 

        System.out.println("Error in stringToPrivateKey");
        e.printStackTrace();
    

    return returnKey; 



public static String publicKeyToString(PublicKey p) 

    byte[] publicKeyBytes = p.getEncoded();
    BASE64Encoder encoder = new BASE64Encoder();
    return encoder.encode(publicKeyBytes);


public static String privateKeyToString(PrivateKey p) 

    byte[] privateKeyBytes = p.getEncoded();
    BASE64Encoder encoder = new BASE64Encoder();
    return encoder.encode(privateKeyBytes);


我使用的驱动代码是:

import java.security.PrivateKey;
import java.security.PublicKey;

public class SQLServerTest 
public static void main(String[] args) throws Exception 


    ServerSQLManager s = new ServerSQLManager();
    ServerUser user = new ServerUser("testUser", "pass123");
    s.getKeys(user);


    PublicKey testKey = user.getPublicKey();
    System.out.println(testKey);
    PrivateKey testKey2 = user.getPrivateKey();
    System.out.println(testKey2);


当我运行它时,我得到了一个不合适的密钥规范,谁能指出我正确的方向?控制台输出为:

Error in stringToPrivateKey


java.security.spec.InvalidKeySpecException: Inappropriate key specification
at sun.security.provider.DSAKeyFactory.engineGeneratePrivate(Unknown Source)
at java.security.KeyFactory.generatePrivate(Unknown Source)
at KeyConvert.stringToPrivateKey(KeyConvert.java:61)
at ServerSQLManager.getKeys(ServerSQLManager.java:128)
at SQLServerTest.main(SQLServerTest.java:20)

Sun DSA Public Key
     Parameters:DSA
    p:     fd7f5381 1d751229 52df4a9c 2eece4e7 f611b752 3cef4400 c31e3f80 b6512669
    455d4022 51fb593d 8d58fabf c5f5ba30 f6cb9b55 6cd7813b 801d346f f26660b7
    6b9950a5 a49f9fe8 047b1022 c24fbba9 d7feb7c6 1bf83b57 e7c6a8a6 150f04fb
    83f6d3c5 1ec30235 54135a16 9132f675 f3ae2b61 d72aeff2 2203199d d14801c7
q:     9760508f 15230bcc b292b982 a2eb840b f0581cf5
g:     f7e1a085 d69b3dde cbbcab5c 36b857b9 7994afbb fa3aea82 f9574c0b 3d078267
    5159578e bad4594f e6710710 8180b449 167123e8 4c281613 b7cf0932 8cc8a6e1
    3c167a8b 547c8d28 e0a3ae1e 2bb3a675 916ea37f 0bfa2135 62f1fb62 7a01243b
    cca4f1be a8519089 a883dfe1 5ae59f06 928b665e 807b5525 64014c3b fecf492a

    y:
    5210e849 24d90208 56802887 dfaededf 78d3e6d0 d2e59a1c fb52dde8 96147784
    b2589365 2529414c 8265b61d c1fe6d98 cee0eea3 cce1e366 cd621ca7 41e3a94f
    9c15bfcb eb860d19 21efd574 79bb5b15 8159b1cb e3fc7f76 f85a6fc1 8d65afc6
    7c4fafda 503b01b5 99752ee4 2408ad80 1d983579 b00e2120 6d735874 ccaea1c0

null

我知道我不应该使用 sun.misc.* 库,我们正在研究 Apache 版本,但仍想弄清楚(而且它永远不会是生产代码)

任何建议表示赞赏。

【问题讨论】:

不要这样做。字符串不是二进制数据的容器。 您是否尝试过调试此问题以缩小其原因?当您转储所有文件时,这里没有人会为您调试代码。 【参考方案1】:

与您一样,公钥使用 X509EncodedKeySpec 存储,但私钥使用 PKCS8EncodedKeySpec。比如这样:

public static PrivateKey loadPrivateKey(String key64) throws GeneralSecurityException 
    byte[] clear = base64Decode(key64);
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(clear);
    KeyFactory fact = KeyFactory.getInstance("DSA");
    PrivateKey priv = fact.generatePrivate(keySpec);
    Arrays.fill(clear, (byte) 0);
    return priv;



public static PublicKey loadPublicKey(String stored) throws GeneralSecurityException 
    byte[] data = base64Decode(stored);
    X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
    KeyFactory fact = KeyFactory.getInstance("DSA");
    return fact.generatePublic(spec);


public static String savePrivateKey(PrivateKey priv) throws GeneralSecurityException 
    KeyFactory fact = KeyFactory.getInstance("DSA");
    PKCS8EncodedKeySpec spec = fact.getKeySpec(priv,
            PKCS8EncodedKeySpec.class);
    byte[] packed = spec.getEncoded();
    String key64 = base64Encode(packed);

    Arrays.fill(packed, (byte) 0);
    return key64;



public static String savePublicKey(PublicKey publ) throws GeneralSecurityException 
    KeyFactory fact = KeyFactory.getInstance("DSA");
    X509EncodedKeySpec spec = fact.getKeySpec(publ,
            X509EncodedKeySpec.class);
    return base64Encode(spec.getEncoded());



public static void main(String[] args) throws Exception 
    KeyPairGenerator gen = KeyPairGenerator.getInstance("DSA");
    KeyPair pair = gen.generateKeyPair();

    String pubKey = savePublicKey(pair.getPublic());
    PublicKey pubSaved = loadPublicKey(pubKey);
    System.out.println(pair.getPublic()+"\n"+pubSaved);

    String privKey = savePrivateKey(pair.getPrivate());
    PrivateKey privSaved = loadPrivateKey(privKey);
    System.out.println(pair.getPrivate()+"\n"+privSaved);

【讨论】:

PKCS8EncodedKeySpec 是诀窍。不幸的是 Sun/Oracle 的教程是错误的。 这仍然是一个有效的答案吗?当我执行 loadPrivateKey(String key) 方法时,出现以下错误:java.security.spec.InvalidKeySpecException:不适当的密钥规范:DER 输入,整数标记错误 @JuanCarlos 仍然有效。该错误消息意味着您正在阅读的私钥并非您认为的那样。此代码需要使用 ASN.1 可分辨编码规则 (DER) 编码的私钥。如果输入是 PEM 格式,或者在私钥周围添加了文本,则不起作用。 正是您编写密钥生成器所需要的

以上是关于将字符串转换为加密密钥,反之亦然java的主要内容,如果未能解决你的问题,请参考以下文章

将 Java 日期转换为 XML 日期格式(反之亦然)

java的RSA签名验签怎么转化成c

destring — 将字符串变量转换为数字变量,反之亦然

如何将字符串转换为十六进制字节数组? [复制]

将 Elixir 加密和解密逻辑映射到 PHP,反之亦然

如何将 16 位值的数组转换为 base64?