Java 何时使用X509EncodedKeySpec与RSAPublicKeySpec?

Java 何时使用X509EncodedKeySpec与RSAPublicKeySpec?,java,encryption,public-key-encryption,Java,Encryption,Public Key Encryption,我有一个文本文件中的证书,其内容如下: -----BEGIN PUBLIC KEY----- xxxx xxxx xxxx -----END PUBLIC KEY----- 我相信这是pem编码的证书?因此,我想现在加载它,我正在尝试以下操作: X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec( readFileToByteArray("keyfile")); 但我得到一个InvalidKeySpec例外 如果我加载文

我有一个文本文件中的证书,其内容如下:

-----BEGIN PUBLIC KEY-----
xxxx
xxxx
xxxx
-----END PUBLIC KEY-----
我相信这是pem编码的证书?因此,我想现在加载它,我正在尝试以下操作:

X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
    readFileToByteArray("keyfile"));
但我得到一个InvalidKeySpec例外

如果我加载文件,切断开始/结束页眉/页脚,然后base64解码“xxxx”内容,我没有收到任何投诉:

String contents = readFileToString("keyfile");
contents = contents.replace("-----BEGIN PUBLIC KEY-----", "");
contents = contents.replace("-----END PUBLIC KEY-----", "");
byte[] prepared = Base64.decode(contents);

// ok.
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(prepared);
这是加载密钥文件的正确方法吗?我看到还有一个类,基于名称,它似乎是我在这里感兴趣的东西。但我相信这只是为了生成证书,而不是读取现有的证书


谢谢

这里有一个很好的通用密钥格式摘要。正如javadocs所指出的,这个类的设计目的是在X.509标准的ASN.1结构和Java公钥格式之间进行转换。而且由于第一个链接表明,一个文件的形式

-----开始公钥------
xxxx
xxxx
-----结束公钥-----

确实是SubjectPublicKeyInfo,您正在正确解析该文件。您缺少的最后一步是将X509EncodedKeySpec转换为公钥。这就是系统的功能。将您的示例再扩展两行

KeyFactory kf = KeyFactory.getInstance("RSA"); // Assuming this is an RSA key
RSAPublicKey rsaPubKey = (RSAPublicKey) kf.generatePublic(publicKeySpec);

答案并不简单。在将RSA公钥字符串(如上所述以PEM格式编码)加载到
java.security.PublicKey
对象时,下面的代码对我很有用。注:应提前剥离集管和端部

    public PublicKey convertToPublicKey(String publicKeyString) {
    try {
        byte[] decodedPublicKey = Base64.decode(publicKeyString, Base64.DEFAULT);
        org.spongycastle.asn1.ASN1InputStream in = new org.spongycastle.asn1.ASN1InputStream(decodedPublicKey);
        org.spongycastle.asn1.ASN1Primitive obj = in.readObject();
        org.spongycastle.asn1.pkcs.RSAPublicKey keyStruct = org.spongycastle.asn1.pkcs.RSAPublicKey.getInstance(obj);
        java.security.spec.RSAPublicKeySpec keySpec = new java.security.spec.RSAPublicKeySpec(keyStruct.getModulus(), keyStruct.getPublicExponent());
        java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(keySpec);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
然后,可以使用
java.security.PublicKey
实例对字符串进行加密,如下所示:

Cipher rsaCipher = Cipher.getInstance("RSA/None/PKCS1Padding", "SC");
rsaCipher.init(Cipher.ENCRYPT_MODE, apiPublicKey);
byte[] ENCRYPTED_YOUR_STRING = rsaCipher.doFinal(YOUR_STRING);
然后可以通过以下方式将字节转换为字符串:
Base64.encodeToString(加密的字符串,Base64.DEFAULT)

该解决方案在Android API 25平台上进行测试,spongycastle 1.56使用该类

注意:仅使用小于129字节的字符串

public class RSA
{
private PublicKey internalPublicKey;
private PrivateKey internalPrivateKey;
private KeyPairGenerator kpg = null;
private int SIZE = 4096;

public RSA(int size)
{
    try
    {
        SIZE = size;
        kpg = KeyPairGenerator.getInstance("RSA");
        init();
    }
    catch(Exception e){}
}

public RSA()
{
    this(1024);
}

private void init()
{
    kpg.initialize(SIZE, new SecureRandom());

    KeyPair kp = kpg.genKeyPair();
    internalPublicKey = kp.getPublic();
    internalPrivateKey = kp.getPrivate();
}

public int getSize()
{
    return SIZE;
}

public PublicKey getPublic()
{
    return internalPublicKey;
}

public PrivateKey getPrivate()
{
    return internalPrivateKey;
}

public String getPublicModule()
{
    String s = internalPublicKey.toString();
    return s.substring(s.indexOf("modulus")+8, s.indexOf(",publicExponent"));
}

public String getPublicExponent()
{
    String s = internalPublicKey.toString();
    return s.substring(s.indexOf("publicExponent")+15, s.lastIndexOf("}"));
}

public String getPrivateExponent()
{
    String s = internalPrivateKey.toString();
    return s.substring(s.indexOf("privateExponent")+16, s.indexOf(",primeP"));
}

public String getPrivatePrimP()
{
    String s = internalPrivateKey.toString();
    return s.substring(s.indexOf("primeP=")+7, s.indexOf(",primeQ"));
}

public String getPrivatePrimQ()
{
    String s = internalPrivateKey.toString();
    return s.substring(s.indexOf("primeQ=")+7, s.indexOf(",primeExponentP"));
}

public String getPrivatePrimExponentP()
{
    String s = internalPrivateKey.toString();
    return s.substring(s.indexOf("primeExponentP=")+15, s.indexOf(",primeExponentQ"));
}

public String getPrivatePrimExponentQ()
{
    String s = internalPrivateKey.toString();
    return s.substring(s.indexOf("primeExponentQ=")+15, s.indexOf(",crtCoefficient"));
}

public String getPrivateCrtCoefficient()
{
    String s = internalPrivateKey.toString();
    return s.substring(s.indexOf("crtCoefficient=")+15, s.lastIndexOf(","));
}

public byte[] getPublicKey()
{
    return internalPublicKey.getEncoded();
}

public byte[] getPrivateKey()
{
    return internalPrivateKey.getEncoded();
}

public String getPublicKeyAsString()
{
    return Base64.encodeToString(internalPublicKey.getEncoded(), Base64.DEFAULT);
}

public String getPrivateKeyAsString()
{
    return Base64.encodeToString(internalPrivateKey.getEncoded(), Base64.DEFAULT);
}

public byte[] getEncrypt(String plain)
{
    try
    {
        //Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, internalPublicKey);

        return cipher.doFinal(plain.getBytes("UTF-8"));
    }
    catch(Exception e)
    {
        ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getEncrypt(String x), ", Constants.DEFAULT_ALERT_STATE);
    }

    return null;
}

public String getStringEncrypt(String plain)
{
    return new String(getEncrypt(plain), Charset.forName("UTF-8"));
}

public byte[] getDecrypt(byte[] encryptedBytes)
{
    try
    {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, internalPrivateKey);

        return cipher.doFinal(encryptedBytes);
    }
    catch(Exception e)
    {
        ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getDecrypt(byte[] x), ", Constants.DEFAULT_ALERT_STATE);
    }

    return null;
}

public byte[] getDecrypt(String encrypted)
{
    return getDecrypt(encrypted.getBytes());
}

public String getStringDecrypt(byte[] encryptedBytes)
{
    return new String(getDecrypt(encryptedBytes), Charset.forName("UTF-8"));
}

public String getStringDecrypt(String encrypted)
{
    return new String(getDecrypt(encrypted), Charset.forName("UTF-8"));
}

public static byte[] getEncrypt(String plain, String modulus, String exponent)
{
    try
    {
        BigInteger modBigInteger = new BigInteger(modulus, 16);
        BigInteger exBigInteger = new BigInteger(exponent, 16);
        RSAPublicKeySpec spec = new RSAPublicKeySpec(modBigInteger, exBigInteger);

        KeyFactory factory = KeyFactory.getInstance("RSA");
        PublicKey pk = factory.generatePublic(spec);

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pk);

        return cipher.doFinal(plain.getBytes("UTF-8"));
    }
    catch(Exception e)
    {
        ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: getEncrypt, ", Constants.DEFAULT_ALERT_STATE);
    }

    return null;
}

public static String getStringEncrypt(final String plain, String modulus, String exponent)
{
    return Base64.encodeToString(getEncrypt(plain, modulus, exponent), Base64.DEFAULT);
}

public static byte[] getDecrypt(byte[] encryptedBytes, String modulus, String publicExpo, String privateExpo, String primP, String primQ, String ePrimP, String ePrimQ, String cof)
{
    try
    {
        BigInteger module = new BigInteger(modulus, 16);
        BigInteger expo1 = new BigInteger(publicExpo, 16);
        BigInteger expo2 = new BigInteger(privateExpo, 16);
        BigInteger prim_P = new BigInteger(primP, 16);
        BigInteger prim_Q = new BigInteger(primQ, 16);
        BigInteger prim_EP = new BigInteger(ePrimP, 16);
        BigInteger prim_EQ = new BigInteger(ePrimQ, 16);
        BigInteger coefficient = new BigInteger(cof, 16);
        /*BigInteger module = new BigInteger(1, Base64.encode(modulus.getBytes(), Base64.DEFAULT));
        BigInteger expo1 = new BigInteger(1, Base64.encode(publicExpo.getBytes(), Base64.DEFAULT));
        BigInteger expo2 = new BigInteger(1, Base64.encode(privateExpo.getBytes(), Base64.DEFAULT));
        BigInteger prim_P = new BigInteger(1, Base64.encode(primP.getBytes(), Base64.DEFAULT));
        BigInteger prim_Q = new BigInteger(1, Base64.encode(primQ.getBytes(), Base64.DEFAULT));
        BigInteger prim_EP = new BigInteger(1, Base64.encode(ePrimP.getBytes(), Base64.DEFAULT));
        BigInteger prim_EQ = new BigInteger(1, Base64.encode(ePrimQ.getBytes(), Base64.DEFAULT));
        BigInteger coefficient = new BigInteger(1, Base64.encode(cof.getBytes(), Base64.DEFAULT));*/

        RSAPrivateCrtKeySpec spec = new RSAPrivateCrtKeySpec(module, expo1, expo2, prim_P, prim_Q, prim_EP, prim_EQ, coefficient);

        KeyFactory factory = KeyFactory.getInstance("RSA");
        PrivateKey pk = factory.generatePrivate(spec);

        Cipher cipher1 = Cipher.getInstance("RSA");
        cipher1.init(Cipher.DECRYPT_MODE, pk);

        //return cipher1.doFinal(Base64.decode(encryptedBytes, Base64.DEFAULT));
        return cipher1.doFinal(encryptedBytes);
    }
    catch(Exception e)
    {
        ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "", Constants.DEFAULT_ALERT_STATE);
    }

    return null;
}

public static String getStringDecrypt(byte[] encryptedBytes, String modulus, String publicExpo, String privateExpo, String primP, String primQ, String ePrimP, String ePrimQ, String cof)
{
    return Converter.byteToString_UTF8(getDecrypt(encryptedBytes, modulus, publicExpo, privateExpo, primP, primQ, ePrimP, ePrimQ, cof));
}

public static byte[] getDecrypt(final byte[] encryptedBytes, byte[] privateKey)
{
    try
    {
        KeyFactory keyFac = KeyFactory.getInstance("RSA");
        KeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
        PrivateKey pk = keyFac.generatePrivate(keySpec);

        Cipher cipher1 = Cipher.getInstance("RSA");
        cipher1.init(Cipher.DECRYPT_MODE, pk);
        return cipher1.doFinal(encryptedBytes);
    }
    catch(Exception e)
    {
        ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "", Constants.DEFAULT_ALERT_STATE);
    }

    return null;
}

public static String getStringDecrypt(final byte[] encryptedBytes, byte[] privateKey)
{
    return Converter.byteToString_UTF8(getDecrypt(encryptedBytes, privateKey));
}

public static String sign(String plainText, PrivateKey privateKey)
{
    try
    {
        Signature privateSignature = Signature.getInstance("SHA256withRSA");
        privateSignature.initSign(privateKey);
        privateSignature.update(plainText.getBytes());

        byte[] signature = privateSignature.sign();

        return Base64.encodeToString(signature, Base64.DEFAULT);
    }
    catch(Exception e)
    {
        ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: sign(), ", Constants.DEFAULT_ALERT_STATE);
    }

    return null;
}

public static boolean verify(String plainText, String signature, PublicKey publicKey)
{
    Signature publicSignature;

    try
    {
        publicSignature = Signature.getInstance("SHA256withRSA");
        publicSignature.initVerify(publicKey);
        publicSignature.update(plainText.getBytes());

        byte[] signatureBytes = Base64.decode(signature, Base64.DEFAULT);

        return publicSignature.verify(signatureBytes);
    }
    catch(Exception e)
    {
        ThreadHelper.exceptionAlert(e, Constants.TAG_FOR_LOG, "Err: verify(), ", Constants.DEFAULT_ALERT_STATE);
    }

    return false;
}
}

“我有证书”。。。不,您有公钥,而不是证书。但是,您所做的获取关键实例的操作是正确的。