java.lang.IllegalArgumentException:解密字符串时,base-64为坏 [英] java.lang.IllegalArgumentException: bad base-64 when decrypting string

查看:2649
本文介绍了java.lang.IllegalArgumentException:解密字符串时,base-64为坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述





更新



对于Android API 19 ,您只需使用以前的 KeyStore API KeyPairGeneratorSpec 而不是 KeyGenParameterSpec 像这样:

 尝试{
Calendar start = Calendar.getInstance();
日历结束= Calendar.getInstance();
end.add(Calendar.YEAR,1);

KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this)
.setAlias(key1)
.setSubject(new X500Principal(CN = Sample Name,O = Android Authority )
.setSerialNumber(BigInteger.ONE)
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.build();

KeyPairGenerator generator = KeyPairGenerator.getInstance(RSA,AndroidKeyStore);
generator.initialize(spec);

// android 6中的错误:InvalidKeyException:需要RSA私钥或公钥AndroidOpenSSL
// android 5中的错误:NoSuchProviderException:提供程序不可用:AndroidKeyStoreBCWorkaround
String provider = Build .VERSION.SDK_INT< Build.VERSION_CODES.M? AndroidOpenSSL:AndroidKeyStoreBCWorkaround;

KeyPair keyPair = generator.generateKeyPair();

密码inCipher = Cipher.getInstance(RSA / ECB / PKCS1Padding,提供者);
inCipher.init(Cipher.ENCRYPT_MODE,keyPair.getPublic());

密码outCipher = Cipher.getInstance(RSA / ECB / PKCS1Padding,提供者);
outCipher.init(Cipher.DECRYPT_MODE,keyPair.getPrivate());


ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(
outputStream,inCipher);

String plainText =这是一个文本;

cipherOutputStream.write(plainText.getBytes(UTF-8));
cipherOutputStream.close();

String ecryptedText = Base64.encodeToString(outputStream.toByteArray(),Base64.DEFAULT);
Log.d(TAG,Encrypt =+ ecryptedText);

String cipherText = ecryptedText;
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(Base64.decode(cipherText,Base64.DEFAULT)),outCipher);

ArrayList< Byte> values = new ArrayList<>();
int nextByte;
while((nextByte = cipherInputStream.read())!= -1){
values.add((byte)nextByte);
}

byte [] bytes = new byte [values.size()]; (int i = 0; i< bytes.length; i ++){
bytes [i] = values.get(i).byteValue();

}

String finalText = new String(bytes,0,bytes.length,UTF-8);
Log.d(TAG,Decrypt =+ finalText);
} catch(javax.crypto.NoSuchPaddingException e){
Log.e(TAG,Log.getStackTraceString(e));
} catch(IOException e){
Log.e(TAG,Log.getStackTraceString(e));
} catch(NoSuchAlgorithmException e){
Log.e(TAG,Log.getStackTraceString(e));
} catch(NoSuchProviderException e){
Log.e(TAG,Log.getStackTraceString(e));
} catch(InvalidAlgorithmParameterException e){
Log.e(TAG,Log.getStackTraceString(e));
} catch(InvalidKeyException e){
Log.e(TAG,Log.getStackTraceString(e));
} catch(UnsupportedOperationException e){
Log.e(TAG,Log.getStackTraceString(e));
}


I am trying to encrypt a string using the KeyStore and used this post as reference.

KeyPairGeneratorSpec replacement with KeyGenParameterSpec.Builder equivalents - Keystore operation failed

yet, I keep getting this "bad base-64" when I decrypt the string. I am not understanding exactly how to fix this. I understand that the encrypted string contains characters that the decryptor does not know. But I don't understand the fix.

I saw some posts like those, but did not help much since there is no code on the answers.

java.lang.IllegalArgumentException: bad base-64

This is a snipped of my the test code, can someone show me how I decrpyt my string?

Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
inCipher.init(Cipher.ENCRYPT_MODE, publicKey);

Cipher outCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
outCipher.init(Cipher.DECRYPT_MODE, privateKey);

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(
        outputStream, inCipher);
cipherOutputStream.write(plainText.getBytes("UTF-8"));
cipherOutputStream.close();

String ecryptedText = outputStream.toString();
Log.d(TAG, "Encrypt = " + ecryptedText);

String cipherText = ecryptedText;
CipherInputStream cipherInputStream = new CipherInputStream(
        new ByteArrayInputStream(Base64.decode(cipherText, Base64.DEFAULT)), outCipher);
ArrayList<Byte> values = new ArrayList<>();
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
    values.add((byte)nextByte);
}

byte[] bytes = new byte[values.size()];
for(int i = 0; i < bytes.length; i++) {
    bytes[i] = values.get(i).byteValue();
}

String finalText = new String(bytes, 0, bytes.length, "UTF-8");
Log.d(TAG, "Decrypt = " + ecryptedText);

解决方案

Here is a working example on how you can use Android KeyStore to Encrypt/Decrypt memory strings by using ByteArrayOutputStream and ByteArrayInputStream. Notice the provider change, for >= 6 use "AndroidKeyStoreBCWorkaround" and for older versions use "AndroidOpenSSL". Also, you have to encode the encrypted data to Base64 string using Base64.encodeToString like this:

String ecryptedText = Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT);

My final working example based on your code

try {
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
            KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
    keyPairGenerator.initialize(
            new KeyGenParameterSpec.Builder(
                    "key1",
                    KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
                    .build());
    KeyPair keyPair = keyPairGenerator.generateKeyPair();

    // error in android 6: InvalidKeyException: Need RSA private or public key AndroidOpenSSL
    // error in android 5: NoSuchProviderException: Provider not available: AndroidKeyStoreBCWorkaround
    String provider = Build.VERSION.SDK_INT < Build.VERSION_CODES.M ? "AndroidOpenSSL" : "AndroidKeyStoreBCWorkaround";

    Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
    inCipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());

    Cipher outCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
    outCipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    CipherOutputStream cipherOutputStream = new CipherOutputStream(
            outputStream, inCipher);

    String plainText = "This is a text";

    cipherOutputStream.write(plainText.getBytes("UTF-8"));
    cipherOutputStream.close();

    String ecryptedText = Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT);
    Log.d(TAG, "Encrypt = " + ecryptedText);

    String cipherText = ecryptedText;
    CipherInputStream cipherInputStream = new CipherInputStream(
            new ByteArrayInputStream(Base64.decode(cipherText, Base64.DEFAULT)), outCipher);

    ArrayList<Byte> values = new ArrayList<>();
    int nextByte;
    while ((nextByte = cipherInputStream.read()) != -1) {
        values.add((byte)nextByte);
    }

    byte[] bytes = new byte[values.size()];
    for(int i = 0; i < bytes.length; i++) {
        bytes[i] = values.get(i).byteValue();
    }

    String finalText = new String(bytes, 0, bytes.length, "UTF-8");
    Log.d(TAG, "Decrypt = " + finalText);
} catch (javax.crypto.NoSuchPaddingException e) {
    Log.e(TAG, Log.getStackTraceString(e));
} catch (IOException e) {
    Log.e(TAG, Log.getStackTraceString(e));
} catch (NoSuchAlgorithmException e) {
    Log.e(TAG, Log.getStackTraceString(e));
} catch (NoSuchProviderException e) {
    Log.e(TAG, Log.getStackTraceString(e));
} catch (InvalidAlgorithmParameterException e) {
    Log.e(TAG, Log.getStackTraceString(e));
} catch (InvalidKeyException e) {
    Log.e(TAG, Log.getStackTraceString(e));
} catch (UnsupportedOperationException e) {
    Log.e(TAG, Log.getStackTraceString(e));
}

OUTPUTS

D/MainActivity: Encrypt = rejkfeas3HgYnZOlC4S/R3KvlMTyiBjr5T6LqWGj9bq6nvpM0KBsoeYtr4OdCLITFX5GojuO4VpB
                Hy11n8zc9JcAx4IFW0Aw0/DfCmMDvIomQItBAaIWewZqNHc0UwS0y/JRhAe8SiTz5sFJ6Abvgax6
                vEfbYT0gzok+qtlfBNQLPvXejquhc0pZBaX1RgKDZyEJh3DBVRaFDgogK8XphaI/xtd1Cww9uO63
                QxA7HfrFUN8rJXrHF4EMi/yrDxs2xVHGF0v21xeuXRwLW9JXYn4fFAJJ0Jr8N5f03UDuKeNlI568
                RFVOGH7WpOLvKN4CDlsC+DT4Z8YVIOdtS/tO+Q==
D/MainActivity: Decrypt = This is a text

UPDATE

For Android API 19, you just have to use the previous KeyStore API KeyPairGeneratorSpec instead of KeyGenParameterSpec like this:

try {
    Calendar start = Calendar.getInstance();
    Calendar end = Calendar.getInstance();
    end.add(Calendar.YEAR, 1);

    KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this)
        .setAlias("key1")
        .setSubject(new X500Principal("CN=Sample Name, O=Android Authority"))
        .setSerialNumber(BigInteger.ONE)
        .setStartDate(start.getTime())
        .setEndDate(end.getTime())
        .build();

    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
    generator.initialize(spec);

    // error in android 6: InvalidKeyException: Need RSA private or public key AndroidOpenSSL
    // error in android 5: NoSuchProviderException: Provider not available: AndroidKeyStoreBCWorkaround
    String provider = Build.VERSION.SDK_INT < Build.VERSION_CODES.M ? "AndroidOpenSSL" : "AndroidKeyStoreBCWorkaround";

    KeyPair keyPair = generator.generateKeyPair();

    Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
    inCipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());

    Cipher outCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
    outCipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());


    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    CipherOutputStream cipherOutputStream = new CipherOutputStream(
            outputStream, inCipher);

    String plainText = "This is a text";

    cipherOutputStream.write(plainText.getBytes("UTF-8"));
    cipherOutputStream.close();

    String ecryptedText = Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT);
    Log.d(TAG, "Encrypt = " + ecryptedText);

    String cipherText = ecryptedText;
    CipherInputStream cipherInputStream = new CipherInputStream(
            new ByteArrayInputStream(Base64.decode(cipherText, Base64.DEFAULT)), outCipher);

    ArrayList<Byte> values = new ArrayList<>();
    int nextByte;
    while ((nextByte = cipherInputStream.read()) != -1) {
        values.add((byte)nextByte);
    }

    byte[] bytes = new byte[values.size()];
    for(int i = 0; i < bytes.length; i++) {
        bytes[i] = values.get(i).byteValue();
    }

    String finalText = new String(bytes, 0, bytes.length, "UTF-8");
    Log.d(TAG, "Decrypt = " + finalText);
} catch (javax.crypto.NoSuchPaddingException e) {
    Log.e(TAG, Log.getStackTraceString(e));
} catch (IOException e) {
    Log.e(TAG, Log.getStackTraceString(e));
} catch (NoSuchAlgorithmException e) {
    Log.e(TAG, Log.getStackTraceString(e));
} catch (NoSuchProviderException e) {
    Log.e(TAG, Log.getStackTraceString(e));
} catch (InvalidAlgorithmParameterException e) {
    Log.e(TAG, Log.getStackTraceString(e));
} catch (InvalidKeyException e) {
    Log.e(TAG, Log.getStackTraceString(e));
} catch (UnsupportedOperationException e) {
    Log.e(TAG, Log.getStackTraceString(e));
}

这篇关于java.lang.IllegalArgumentException:解密字符串时,base-64为坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆