Объекты Chyper SharedPreferences GSON

Я хочу сохранить зашифрованный объект профиля в SharedPreferences с помощью gson.

Вот мой код:

public void saveProfile(Profile newProfile) {
  try {
    Log.i(C.TAG, newProfile.toString());

    SharedPreferences.Editor editor = prefs.edit();
    String profileJSONfied = new Gson().toJson(newProfile);
    Log.i(C.TAG, profileJSONfied);

    byte[] cleartext = profileJSONfied.getBytes(HTTP.UTF_8);
    Log.i(C.TAG, cleartext.toString());

    Cipher cipher = Cipher.getInstance("DES");
    cipher.init(Cipher.ENCRYPT_MODE, key);
    String encrypedProfile = Base64.encodeToString(cipher.doFinal(cleartext), Base64.DEFAULT);
    Log.i(C.TAG, encrypedProfile);

    editor.putString(PROFILE, encrypedProfile);
    editor.commit();
    profile = newProfile;
  } catch (Exception e) {
    Log.i(C.TAG, e.getMessage());
  }
}

public Profile loadProfile() {
  try {
    Cipher cipher = Cipher.getInstance("DES");
    cipher.init(Cipher.DECRYPT_MODE, key);

    Log.i(C.TAG, prefs.getString(PROFILE, null));

    // byte[] plainTextProfileBytes = Base64.decode(cipher.doFinal(prefs.getString(PROFILE, null).getBytes(HTTP.UTF_8)), Base64.DEFAULT);
    byte[] plainTextProfileBytes = Base64.decode(prefs.getString(PROFILE, null).getBytes(HTTP.UTF_8), Base64.DEFAULT);
    Log.i(C.TAG, new String(plainTextProfileBytes, HTTP.UTF_8));

    profile = new Gson().fromJson(new String(plainTextProfileBytes, HTTP.UTF_8), PROFILE_TYPE);
    Log.i(C.TAG, profile.toString());

  } catch (Exception e) {
    Log.i(C.TAG, e.getMessage());
  }
  return profile;
}

Вот пример вывода (упорядоченный по порядку журнала):

saveProfile:
Profile@4146a1d8

{"email":"aaa","firstName":"aaa","lastName":"aaa","postal": "aaa", etc etc...}

[B@414819b0

+nLS7XhRoIFPBeC11/h6mMz6hFfc8js03QJ8VwVZH+dPBeC11/h6mJ448CLGPNzz+bU669XpAI8VXchYQJr7mgDwHpeoSrP4BMACydjKpC8Q9atbk9xz6HNqDpNOiqaa75hFM+r9pzm55/E2E2tdjz4s5OzNNppAPzmtS69tZAZLPuYt1kvnJehHa6fDt2o5UCv6VukCwvVgt+UDcCqCKvF22Iv6vdMXWTcm


На данный момент я думаю, что все прошло так, как ожидалось. The problem lies below, decipher operation


loadProfile:(backward process)
+nLS7XhRoIFPBeC11/h6mMz6hFfc8js03QJ8VwVZH+dPBeC11/h6mJ448CLGPNzz+bU669XpAI8VXchYQJr7mgDwHpeoSrP4BMACydjKpC8Q9atbk9xz6HNqDpNOiqaa75hFM+r9pzm55/E2E2tdjz4s5OzNNppAPzmtS69tZAZLPuYt1kvnJehHa6fDt2o5UCv6VukCwvVgt+UDcCqCKvF22Iv6vdMXWTcm

�r��xQ��O���z���W��;4�|WY�O���z��8�"�‹���:������ ]�X@�������J������ʤ/�[��s�sj�N����E3��9���6k]�>,���6�@ ?9�K�mdK>�-�K�%�Gk�÷j9P+�V���`��p*�*�v؋��Y7&���-A

java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 21

Если я вместо:

byte[] plainTextProfileBytes = Base64.decode(prefs.getString(PROFILE,null).getBytes(HTTP.UTF_8), Base64.DEFAULT);

Я использую:

byte[] plainTextProfileBytes = Base64.decode(cipher.doFinal(prefs.getString(PROFILE, null).getBytes(HTTP.UTF_8)), Base64.DEFAULT);

Ошибка будет:

pad block corrupted

Что я здесь упускаю?
Спасибо за ваше время.


person GuilhE    schedule 17.05.2013    source источник


Ответы (1)


Итак, я нашел решение!
Для начала я немного изменил свой код. Я создал класс myPBEkey с двумя методами, шифрованием и дешифрованием, оба возвращают объект Cipher с соответствующим "opmode":

Затем я изменил код методов saveProfile и loadProfile на:

public void saveProfile(Profile newProfile) {
    try {
            SharedPreferences.Editor editor = prefs.edit();

            String profileJSONfied = new Gson().toJson(newProfile);             
            byte[] encryptedProfile = pbeKey.encrypt().doFinal(profileJSONfied.getBytes(HTTP.UTF_8));       
            byte[] encryptedProfileBase64 = Base64.encode(encryptedProfile, Base64.DEFAULT);            

            editor.putString(PROFILE, new String(encryptedProfileBase64, HTTP.UTF_8));
            editor.commit();
            profile = newProfile;
    } catch (Exception e) {
            Log.i(C.TAG, e.getMessage());
    }
}


public Profile loadProfile() {
    if (profile == null) {
        try {                   
            byte[] decodedProfileBase64 = Base64.decode(prefs.getString(PROFILE, null), Base64.DEFAULT);
            byte[] plainTextProfileBytes = pbeKey.decrypt().doFinal(decodedProfileBase64);

            profile = new Gson().fromJson(new String(plainTextProfileBytes, HTTP.UTF_8), PROFILE_TYPE);

        } catch (Exception e) {
            Log.i(C.TAG, e.getMessage());
    }
return profile;

Я думаю, что проблему решило отделение шифрования/дешифрования от Base64 кодирования/декодирования, поэтому сначала мы шифруем, а затем кодируем зашифрованное byte[] и, наконец, сохраняем его. То же самое происходит при расшифровке, сначала мы декодируем зашифрованный профиль base64, а затем расшифровываем декодированный byte[]. Вуаля!

Спасибо за ваше время, надеюсь, что это поможет вам.

person GuilhE    schedule 20.05.2013