2016-12-06 5 views
3

Я пытаюсь зашифровать строку с помощью KeyStore и использовать этот пост в качестве ссылки.java.lang.IllegalArgumentException: bad base-64 при расшифровке строки

KeyPairGeneratorSpec replacement with KeyGenParameterSpec.Builder equivalents - Keystore operation failed

еще, я получаю эту "плохую базу-64", когда я расшифровать строку. Я не понимаю, как это исправить. Я понимаю, что зашифрованная строка содержит символы, которые дешифратор не знает. Но я не понимаю, что исправить.

Я видел несколько сообщений вроде этих, но не очень помог, так как на ответах нет кода.

java.lang.IllegalArgumentException: bad base-64

Это является отрезал мой тестовый код, может кто-то показать мне, как я decrpyt моих строк?

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); 
+0

50 очков моей репутации для грейферов, кто может вставить код, который шифрует и расшифровывает *** в памяти *** строку, использующую хранилище ключей android. Я не могу использовать доступ к файлам или общие настройки для моего приложения. Повторяю, это нужно сделать в памяти. Ключ сохраняется внутри KeyStore. – gmmo

+2

Вы устанавливаете 'cipherText' из' ecryptedText' и пытаетесь его декодировать base64, но это ** не было в основном кодировкой base64 **. Используйте что-то вроде 'ecryptedText = Base64.encode (/ * BAOS */outputStream.toByteArray, Base64.DEFAULT);' –

ответ

1

Вот рабочий пример того, как вы можете использовать AndroidKeyStore для шифрования/дешифрования строк памяти с помощью ByteArrayOutputStream и ByteArrayInputStream. Обратите внимание на изменение поставщика, для >= 6 используйте "AndroidKeyStoreBCWorkaround", а для более старых версий используйте "AndroidOpenSSL". Кроме того, вы должны кодировать зашифрованные данные в Base64 строку с помощью Base64.encodeToString так:

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

Мой окончательный рабочий пример на основе кода

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)); 
} 

ВЫВОДА

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

Android Studio Output

UPDATE

Для Android API 19, вы просто должны использовать предыдущий KeyStore API KeyPairGeneratorSpec вместо KeyGenParameterSpec так:

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)); 
} 
+0

Christos, спасибо за код. Одна вещь, о которой я забыл упомянуть, заключается в том, что она должна работать на API 19. Приведенный выше код работает только с API 23 и выше. Мне нужно поддерживать старые устройства. Не могли бы вы узнать, как заставить его работать на уровне API 19? – gmmo

+1

@gmmo Это очень просто, вам просто нужно использовать старый API-интерфейс KeyStore. Пожалуйста, ознакомьтесь с моим обновленным ответом. –

+0

спасибо, Христос, ты спас меня от кнута! – gmmo

Смежные вопросы