aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src
diff options
context:
space:
mode:
Diffstat (limited to 'OpenKeychain/src')
-rw-r--r--OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/SymmetricTextOperationTests.java4
-rw-r--r--OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareTest.java6
-rw-r--r--OpenKeychain/src/main/AndroidManifest.xml71
-rw-r--r--OpenKeychain/src/main/assets/api.keybase.io.CA.cer38
-rw-r--r--OpenKeychain/src/main/assets/hkps.pool.sks-keyservers.net.CA.cer (renamed from OpenKeychain/src/main/assets/sks-keyservers.netCA.cer)0
-rw-r--r--OpenKeychain/src/main/assets/pgp.mit.edu.cer33
-rw-r--r--OpenKeychain/src/main/java/org/spongycastle/openpgp/jcajce/JcaSkipMarkerPGPObjectFactory.java32
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java36
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/BitInputStream.java130
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/SentenceConfirm.java210
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/WordConfirm.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ExperimentalWordConfirm.java)7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java17
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java113
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java31
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/linked/LinkedTokenResource.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java312
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java154
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java39
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java42
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java385
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java139
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java62
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java36
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java25
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/UploadOperation.java197
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/BenchmarkResult.java50
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ExportResult.java21
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java57
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/UploadResult.java74
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyInputParcel.java14
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java648
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java61
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java24
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignatureChecker.java344
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java47
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java35
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java47
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryFileProvider.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java)105
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java244
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/BackupKeyringParcel.java78
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/BenchmarkInputParcel.java54
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java111
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java122
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/UploadKeyringParcel.java79
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java14
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupActivity.java77
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeFragment.java543
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupRestoreFragment.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupFragment.java)99
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java43
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java37
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java22
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportResetFragment.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java)125
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinFragment.java121
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinRepeatFragment.java152
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java411
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java20
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptFragment.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java)7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java47
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java75
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java44
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java250
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java42
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java115
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java13
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java50
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java72
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java77
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeCaptureActivity.java125
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java84
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java22
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java36
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java86
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java127
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeybaseFragment.java35
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java51
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeySelectableAdapter.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java186
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java80
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java38
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java234
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareLogDialogFragment.java79
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java45
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java57
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ToolableViewAnimator.java26
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java16
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java124
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java198
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelperLollipop.java82
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FilterCursorWrapper.java17
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/OkHttpKeybaseClient.java76
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableProxy.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java19
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java104
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java82
-rw-r--r--OpenKeychain/src/main/res/anim/fade_in_delayed.xml8
-rw-r--r--OpenKeychain/src/main/res/anim/fade_out_delayed.xml8
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_action_encrypt_paste_24dp.pngbin0 -> 590 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-hdpi/ic_check_black_24dp.pngbin0 -> 169 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_action_encrypt_paste_24dp.pngbin0 -> 433 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-mdpi/ic_check_black_24dp.pngbin0 -> 128 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_action_encrypt_paste_24dp.pngbin0 -> 684 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/ic_check_black_24dp.pngbin0 -> 188 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xhdpi/status_signature_expired_cutout_96dp.pngbin0 -> 4973 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_encrypt_paste_24dp.pngbin0 -> 986 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_black_24dp.pngbin0 -> 254 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_action_encrypt_paste_24dp.pngbin0 -> 1290 bytes
-rw-r--r--OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_black_24dp.pngbin0 -> 277 bytes
-rw-r--r--OpenKeychain/src/main/res/layout-land/backup_code_fragment.xml343
-rw-r--r--OpenKeychain/src/main/res/layout-land/qr_code_activity.xml39
-rw-r--r--OpenKeychain/src/main/res/layout-mdpi/backup_code_fragment.xml343
-rw-r--r--OpenKeychain/src/main/res/layout-xhdpi/backup_code_fragment.xml343
-rw-r--r--OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml36
-rw-r--r--OpenKeychain/src/main/res/layout/backup_activity.xml26
-rw-r--r--OpenKeychain/src/main/res/layout/backup_restore_fragment.xml (renamed from OpenKeychain/src/main/res/layout/backup_fragment.xml)22
-rw-r--r--OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml214
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_email_fragment.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_final_fragment.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_name_fragment.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_start_fragment.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/create_yubi_key_blank_fragment.xml8
-rw-r--r--OpenKeychain/src/main/res/layout/create_yubi_key_import_fragment.xml126
-rw-r--r--OpenKeychain/src/main/res/layout/create_yubi_key_import_reset_fragment.xml174
-rw-r--r--OpenKeychain/src/main/res/layout/create_yubi_key_pin_fragment.xml95
-rw-r--r--OpenKeychain/src/main/res/layout/create_yubi_key_pin_repeat_fragment.xml110
-rw-r--r--OpenKeychain/src/main/res/layout/create_yubi_key_wait_fragment.xml18
-rw-r--r--OpenKeychain/src/main/res/layout/decrypt_list_entry.xml89
-rw-r--r--OpenKeychain/src/main/res/layout/encrypt_decrypt_fragment.xml (renamed from OpenKeychain/src/main/res/layout/encrypt_decrypt_overview_fragment.xml)0
-rw-r--r--OpenKeychain/src/main/res/layout/import_keys_activity.xml29
-rw-r--r--OpenKeychain/src/main/res/layout/key_list_fragment.xml31
-rw-r--r--OpenKeychain/src/main/res/layout/linked_create_github_fragment.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/linked_id_item.xml1
-rw-r--r--OpenKeychain/src/main/res/layout/linked_id_view_fragment.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/nfc_operation_activity.xml32
-rw-r--r--OpenKeychain/src/main/res/layout/passphrase_dialog_backup_code.xml151
-rw-r--r--OpenKeychain/src/main/res/layout/qr_code_capture_activity.xml13
-rw-r--r--OpenKeychain/src/main/res/layout/toolbar_tabs.xml2
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_adv_keybase_fragment.xml14
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml17
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_fragment.xml2
-rw-r--r--OpenKeychain/src/main/res/menu-v19/decrypt_bottom_sheet.xml19
-rw-r--r--OpenKeychain/src/main/res/menu/decrypt_bottom_sheet.xml15
-rw-r--r--OpenKeychain/src/main/res/menu/encrypt_text_fragment.xml8
-rw-r--r--OpenKeychain/src/main/res/menu/key_list.xml6
-rw-r--r--OpenKeychain/src/main/res/menu/key_view.xml4
-rw-r--r--OpenKeychain/src/main/res/raw-cs/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-cs/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-de/help_about.md14
-rw-r--r--OpenKeychain/src/main/res/raw-de/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-es/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-es/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-eu/help_about.md16
-rw-r--r--OpenKeychain/src/main/res/raw-eu/help_changelog.md20
-rw-r--r--OpenKeychain/src/main/res/raw-fa/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-fa/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-fi/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-fi/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-fr/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-fr/help_changelog.md28
-rw-r--r--OpenKeychain/src/main/res/raw-it/help_about.md16
-rw-r--r--OpenKeychain/src/main/res/raw-it/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-ja/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-ja/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-nl/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-nl/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-pl/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-pl/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-ru/help_about.md12
-rw-r--r--OpenKeychain/src/main/res/raw-ru/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-sl/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-sl/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-sr/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-sr/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-sv/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-sv/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-tr/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-tr/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-uk/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-uk/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-zh-rTW/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-zh-rTW/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw-zh/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw-zh/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/raw/fp_sentence_adjectives128
-rw-r--r--OpenKeychain/src/main/res/raw/fp_sentence_adverbs64
-rw-r--r--OpenKeychain/src/main/res/raw/fp_sentence_articles8
-rw-r--r--OpenKeychain/src/main/res/raw/fp_sentence_nouns512
-rw-r--r--OpenKeychain/src/main/res/raw/fp_sentence_prepositions32
-rw-r--r--OpenKeychain/src/main/res/raw/fp_sentence_verbs_i128
-rw-r--r--OpenKeychain/src/main/res/raw/fp_sentence_verbs_t128
-rw-r--r--OpenKeychain/src/main/res/raw/fp_word_list (renamed from OpenKeychain/src/main/assets/word_confirm_list.txt)0
-rw-r--r--OpenKeychain/src/main/res/raw/help_about.md8
-rw-r--r--OpenKeychain/src/main/res/raw/help_changelog.md12
-rw-r--r--OpenKeychain/src/main/res/values-cs/strings.xml54
-rw-r--r--OpenKeychain/src/main/res/values-de/strings.xml337
-rw-r--r--OpenKeychain/src/main/res/values-es/strings.xml703
-rw-r--r--OpenKeychain/src/main/res/values-eu/strings.xml211
-rw-r--r--OpenKeychain/src/main/res/values-fa/strings.xml26
-rw-r--r--OpenKeychain/src/main/res/values-fi/strings.xml155
-rw-r--r--OpenKeychain/src/main/res/values-fr/strings.xml293
-rw-r--r--OpenKeychain/src/main/res/values-it/strings.xml57
-rw-r--r--OpenKeychain/src/main/res/values-ja/strings.xml377
-rw-r--r--OpenKeychain/src/main/res/values-nl/strings.xml108
-rw-r--r--OpenKeychain/src/main/res/values-pl/strings.xml44
-rw-r--r--OpenKeychain/src/main/res/values-ru/strings.xml123
-rw-r--r--OpenKeychain/src/main/res/values-sl/strings.xml62
-rw-r--r--OpenKeychain/src/main/res/values-sr/strings.xml154
-rw-r--r--OpenKeychain/src/main/res/values-sv/strings.xml131
-rw-r--r--OpenKeychain/src/main/res/values-tr/strings.xml35
-rw-r--r--OpenKeychain/src/main/res/values-uk/strings.xml32
-rw-r--r--OpenKeychain/src/main/res/values-v23/themes.xml7
-rw-r--r--OpenKeychain/src/main/res/values-zh-rTW/strings.xml72
-rw-r--r--OpenKeychain/src/main/res/values-zh/strings.xml21
-rw-r--r--OpenKeychain/src/main/res/values/arrays.xml8
-rw-r--r--OpenKeychain/src/main/res/values/colors.xml3
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml165
-rw-r--r--OpenKeychain/src/main/res/values/themes.xml8
-rw-r--r--OpenKeychain/src/main/res/xml/gui_preferences.xml10
-rw-r--r--OpenKeychain/src/main/res/xml/passphrase_preferences.xml8
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java12
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/ExportTest.java246
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java6
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/InputDataOperationTest.java8
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java220
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java36
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java6
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java6
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java3
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/util/TestingUtils.java24
258 files changed, 10824 insertions, 5786 deletions
diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/SymmetricTextOperationTests.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/SymmetricTextOperationTests.java
index 498df7299..ba5eb7491 100644
--- a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/SymmetricTextOperationTests.java
+++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/SymmetricTextOperationTests.java
@@ -32,7 +32,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
+import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import static android.support.test.InstrumentationRegistry.getInstrumentation;
@@ -133,7 +133,7 @@ public class SymmetricTextOperationTests {
hasExtra(equalTo(Intent.EXTRA_INTENT), allOf(
hasAction(Intent.ACTION_VIEW),
hasFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION),
- hasData(allOf(hasScheme("content"), hasHost(TemporaryStorageProvider.AUTHORITY))),
+ hasData(allOf(hasScheme("content"), hasHost(TemporaryFileProvider.AUTHORITY))),
hasType("text/plain")
))
)).respondWith(new ActivityResult(Activity.RESULT_OK, null));
diff --git a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareTest.java b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareTest.java
index 63c7dc6de..edc5571fe 100644
--- a/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareTest.java
+++ b/OpenKeychain/src/androidTest/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareTest.java
@@ -34,7 +34,7 @@ import org.junit.runners.MethodSorters;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
+import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import static android.support.test.espresso.Espresso.onView;
@@ -96,7 +96,7 @@ public class ViewKeyAdvShareTest {
hasType("text/plain"),
hasExtra(is(Intent.EXTRA_TEXT), is("openpgp4fpr:c619d53f7a5f96f391a84ca79d604d2f310716a3")),
hasExtra(is(Intent.EXTRA_STREAM),
- allOf(hasScheme("content"), hasHost(TemporaryStorageProvider.AUTHORITY)))
+ allOf(hasScheme("content"), hasHost(TemporaryFileProvider.AUTHORITY)))
))
)).respondWith(new ActivityResult(Activity.RESULT_OK, null));
onView(withId(R.id.view_key_action_fingerprint_share)).perform(click());
@@ -113,7 +113,7 @@ public class ViewKeyAdvShareTest {
hasType("text/plain"),
hasExtra(is(Intent.EXTRA_TEXT), startsWith("----")),
hasExtra(is(Intent.EXTRA_STREAM),
- allOf(hasScheme("content"), hasHost(TemporaryStorageProvider.AUTHORITY)))
+ allOf(hasScheme("content"), hasHost(TemporaryFileProvider.AUTHORITY)))
))
)).respondWith(new ActivityResult(Activity.RESULT_OK, null));
onView(withId(R.id.view_key_action_key_share)).perform(click());
diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml
index e80faff58..79b8dbb27 100644
--- a/OpenKeychain/src/main/AndroidManifest.xml
+++ b/OpenKeychain/src/main/AndroidManifest.xml
@@ -53,19 +53,32 @@
android:name="${applicationId}.WRITE_TEMPORARY_STORAGE"
android:protectionLevel="signature" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.NFC" />
+ <!-- CAMERA permission requested by ZXing library -->
+
+ <!-- contact group -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
- <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
- <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.WRITE_PROFILE" />
+ <!-- storage group -->
+ <!--
+ No need on >= Android 4.4 for WRITE_EXTERNAL_STORAGE, because we use Storage Access Framework,
+ but better not use maxSdkVersion as it causes problems: https://code.google.com/p/android/issues/detail?id=63895
+ -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <!-- READ_EXTERNAL_STORAGE is now dangerous on Android >= 6 -->
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <!-- other group (for free) -->
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.NFC" />
+ <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
+ <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
+
<!-- android:allowBackup="false": Don't allow backup over adb backup or other apps! -->
<application
android:name=".KeychainApplication"
@@ -97,12 +110,12 @@
android:value=".ui.MainActivity" />
<!-- Connect with YubiKeys. This Activity will automatically show/import/create YubiKeys -->
<intent-filter android:label="@string/app_name">
- <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
- <category android:name="android.intent.category.DEFAULT"/>
+ <action android:name="android.nfc.action.NDEF_DISCOVERED" />
+ <category android:name="android.intent.category.DEFAULT" />
<data
- android:scheme="https"
android:host="my.yubico.com"
- android:pathPrefix="/neo"/>
+ android:pathPrefix="/neo"
+ android:scheme="https" />
</intent-filter>
</activity>
<activity
@@ -114,9 +127,7 @@
android:name=".ui.linked.LinkedIdWizard"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/title_linked_create"
- android:parentActivityName=".ui.ViewKeyActivity"
- >
- </activity>
+ android:parentActivityName=".ui.ViewKeyActivity"></activity>
<activity
android:name=".ui.QrCodeViewActivity"
android:label="@string/share_qr_code_dialog_title" />
@@ -210,6 +221,12 @@
<data android:mimeType="text/*" />
<data android:mimeType="message/*" />
</intent-filter>
+ <!-- Android 6 Floating Action Mode -->
+ <intent-filter>
+ <action android:name="android.intent.action.PROCESS_TEXT" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="text/plain" />
+ </intent-filter>
</activity>
<activity
android:name=".ui.DisplayTextActivity"
@@ -439,6 +456,14 @@
android:label="@string/title_key_server_preference"
android:windowSoftInputMode="stateHidden" />
<activity
+ android:name=".ui.BackupActivity"
+ android:configChanges="keyboardHidden|keyboard"
+ android:label="@string/title_backup">
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".ui.MainActivity" />
+ </activity>
+ <activity
android:name=".ui.CertifyKeyActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/title_certify_key">
@@ -458,7 +483,7 @@
android:name=".ui.ImportKeysProxyActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
android:label="@string/app_name"
- android:theme="@android:style/Theme.NoDisplay"
+ android:theme="@style/Theme.Keychain.Transparent"
android:windowSoftInputMode="stateHidden">
<!-- VIEW with fingerprint scheme:
@@ -491,7 +516,7 @@
<data android:mimeType="application/pgp-keys" />
</intent-filter>
</activity>
-
+ <activity android:name=".ui.QrCodeCaptureActivity" />
<activity
android:name=".ui.ImportKeysActivity"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
@@ -683,19 +708,19 @@
android:label="@string/title_log_display" />
<activity
android:name=".ui.ConsolidateDialogActivity"
- android:theme="@android:style/Theme.NoDisplay" />
+ android:theme="@style/Theme.Keychain.Transparent" />
<activity
android:name=".ui.PassphraseDialogActivity"
- android:theme="@android:style/Theme.NoDisplay" />
+ android:theme="@style/Theme.Keychain.Transparent" />
<activity
android:name=".ui.RetryUploadDialogActivity"
- android:theme="@android:style/Theme.NoDisplay" />
+ android:theme="@style/Theme.Keychain.Transparent" />
<activity
android:name=".ui.DeleteKeyDialogActivity"
- android:theme="@android:style/Theme.NoDisplay" />
+ android:theme="@style/Theme.Keychain.Transparent" />
<activity
android:name=".ui.OrbotRequiredDialogActivity"
- android:theme="@android:style/Theme.NoDisplay" />
+ android:theme="@style/Theme.Keychain.Transparent" />
<!--
NOTE: singleTop is set to get NFC foreground dispatch to work.
Then, all NFC intents will be broadcasted to onNewIntent() of this activity!
@@ -705,10 +730,10 @@
-->
<activity
android:name=".ui.NfcOperationActivity"
- android:theme="@style/Theme.Keychain.Light.Dialog"
android:allowTaskReparenting="true"
android:launchMode="singleTop"
- android:taskAffinity=":Nfc" />
+ android:taskAffinity=":Nfc"
+ android:theme="@style/Theme.Keychain.Light.Dialog" />
<activity
android:name=".ui.HelpActivity"
@@ -733,7 +758,7 @@
android:name=".provider.KeychainProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
- android:label="@string/keyserver_sync_settings_title"/>
+ android:label="@string/keyserver_sync_settings_title" />
<!-- Internal classes of the remote APIs (not exported) -->
<activity
@@ -837,7 +862,7 @@
<!-- Storage Provider for temporary decrypted files -->
<provider
- android:name=".provider.TemporaryStorageProvider"
+ android:name=".provider.TemporaryFileProvider"
android:authorities="${applicationId}.tempstorage"
android:exported="true"
android:writePermission="${applicationId}.WRITE_TEMPORARY_STORAGE" />
diff --git a/OpenKeychain/src/main/assets/api.keybase.io.CA.cer b/OpenKeychain/src/main/assets/api.keybase.io.CA.cer
new file mode 100644
index 000000000..c7da715c4
--- /dev/null
+++ b/OpenKeychain/src/main/assets/api.keybase.io.CA.cer
@@ -0,0 +1,38 @@
+-----BEGIN CERTIFICATE-----
+MIIGmzCCBIOgAwIBAgIJAPzhpcIBaOeNMA0GCSqGSIb3DQEBBQUAMIGPMQswCQYD
+VQQGEwJVUzELMAkGA1UECBMCTlkxETAPBgNVBAcTCE5ldyBZb3JrMRQwEgYDVQQK
+EwtLZXliYXNlIExMQzEXMBUGA1UECxMOQ2VydCBBdXRob3JpdHkxEzARBgNVBAMT
+CmtleWJhc2UuaW8xHDAaBgkqhkiG9w0BCQEWDWNhQGtleWJhc2UuaW8wHhcNMTQw
+MTAyMTY0MjMzWhcNMjMxMjMxMTY0MjMzWjCBjzELMAkGA1UEBhMCVVMxCzAJBgNV
+BAgTAk5ZMREwDwYDVQQHEwhOZXcgWW9yazEUMBIGA1UEChMLS2V5YmFzZSBMTEMx
+FzAVBgNVBAsTDkNlcnQgQXV0aG9yaXR5MRMwEQYDVQQDEwprZXliYXNlLmlvMRww
+GgYJKoZIhvcNAQkBFg1jYUBrZXliYXNlLmlvMIICIjANBgkqhkiG9w0BAQEFAAOC
+Ag8AMIICCgKCAgEA3sLA6ZG8uOvmlFvFLVIOURmcQrZyMFKbVu9/TeDiemls3w3/
+JzVTduD+7KiUi9R7QcCW/V1ZpReTfunm7rfACiJ1fpIkjSQrgsvKDLghIzxIS5FM
+I8utet5p6QtuJhaAwmmXn8xX05FvqWNbrcXRdpL4goFdigPsFK2xhTUiWatLMste
+oShI7+zmrgkx75LeLMD0bL2uOf87JjOzbY8x2sUIZLGwPoATyG8WS38ey6KkJxRj
+AhG3p+OTYEjYSrsAtQA6ImbeDpfSHKOB8HF3nVp//Eb4HEiEsWwBRbQXvAWh3DYL
+GukFW0wiO0HVCoWY+bHL/Mqa0NdRGOlLsbL4Z4pLrhqKgSDU8umX9YuNRRaB0P5n
+TkzyU6axHqzq990Gep/I62bjsBdYYp+DjSPK43mXRrfWJl2NTcl8xKAyfsOW+9hQ
+9vwK0tpSicNxfYuUZs0BhfjSZ/Tc6Z1ERdgUYRiXTtohl+SRA2IgZMloHCllVMNj
+EjXhguvHgLAOrcuyhVBupiUQGUHQvkMsr1Uz8VPNDFOJedwucRU2AaR881bknnSb
+ds9+zNLsvUFV+BK7Qdnt/WkFpYL78rGwY47msi9Ooddx6fPyeg3qkJGM6cwn/boy
+w9lQeleYDq8kyJdixIAxtAskNzRPJ4nDu2izTfByQoM8epwAWboc/gNFObMCAwEA
+AaOB9zCB9DAdBgNVHQ4EFgQURqpATOw1gVVrzlqqFKbkfaKXvwowgcQGA1UdIwSB
+vDCBuYAURqpATOw1gVVrzlqqFKbkfaKXvwqhgZWkgZIwgY8xCzAJBgNVBAYTAlVT
+MQswCQYDVQQIEwJOWTERMA8GA1UEBxMITmV3IFlvcmsxFDASBgNVBAoTC0tleWJh
+c2UgTExDMRcwFQYDVQQLEw5DZXJ0IEF1dGhvcml0eTETMBEGA1UEAxMKa2V5YmFz
+ZS5pbzEcMBoGCSqGSIb3DQEJARYNY2FAa2V5YmFzZS5pb4IJAPzhpcIBaOeNMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggIBAA3Z5FIhulYghMuHdcHYTYWc
+7xT5WD4hXQ0WALZs4p5Y+b2Af54o6v1wUE1Au97FORq5CsFXX/kGl/JzzTimeucn
+YJwGuXMpilrlHCBAL5/lSQjA7qbYIolQ3SB9ON+LYuF1jKB9k8SqNp7qzucxT3tO
+b8ZMDEPNsseC7NE2uwNtcW3yrTh6WZnSqg/jwswiWjHYDdG7U8FjMYlRol3wPux2
+PizGbSgiR+ztI2OthxtxNWMrT9XKxNQTpcxOXnLuhiSwqH8PoY17ecP8VPpaa0K6
+zym0zSkbroqydazaxcXRk3eSlc02Ktk7HzRzuqQQXhRMkxVnHbFHgGsz03L533pm
+mlIEgBMggZkHwNvs1LR7f3v2McdKulDH7Mv8yyfguuQ5Jxxt7RJhUuqSudbEhoaM
+6jAJwBkMFxsV2YnyFEd3eZ/qBYPf7TYHhyzmHW6WkSypGqSnXd4gYpJ8o7LxSf4F
+inLjxRD+H9Xn1UVXWLM0gaBB7zZcXd2zjMpRsWgezf5IR5vyakJsc7fxzgor3Qeq
+Ri6LvdEkhhFVl5rHMQBwNOPngySrq8cs/ikTLTfQVTYXXA4Ba1YyiMOlfaR1LhKw
+If1AkUV0tfCTNRZ01EotKSK77+o+k214n+BAu+7mO+9B5Kb7lMFQcuWCHXKYB2Md
+cT7Yh09F0QpFUd0ymEfv
+-----END CERTIFICATE-----
diff --git a/OpenKeychain/src/main/assets/sks-keyservers.netCA.cer b/OpenKeychain/src/main/assets/hkps.pool.sks-keyservers.net.CA.cer
index 24a2ad2e8..24a2ad2e8 100644
--- a/OpenKeychain/src/main/assets/sks-keyservers.netCA.cer
+++ b/OpenKeychain/src/main/assets/hkps.pool.sks-keyservers.net.CA.cer
diff --git a/OpenKeychain/src/main/assets/pgp.mit.edu.cer b/OpenKeychain/src/main/assets/pgp.mit.edu.cer
new file mode 100644
index 000000000..7249b3611
--- /dev/null
+++ b/OpenKeychain/src/main/assets/pgp.mit.edu.cer
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIFpzCCBI+gAwIBAgIQSCQjuTbnogvWCWWHeCDMbzANBgkqhkiG9w0BAQsFADB2
+MQswCQYDVQQGEwJVUzELMAkGA1UECBMCTUkxEjAQBgNVBAcTCUFubiBBcmJvcjES
+MBAGA1UEChMJSW50ZXJuZXQyMREwDwYDVQQLEwhJbkNvbW1vbjEfMB0GA1UEAxMW
+SW5Db21tb24gUlNBIFNlcnZlciBDQTAeFw0xNDEwMDkwMDAwMDBaFw0xNzEwMDgy
+MzU5NTlaMIHlMQswCQYDVQQGEwJVUzEOMAwGA1UEERMFMDIxMzkxCzAJBgNVBAgT
+Ak1hMRIwEAYDVQQHEwlDYW1icmlkZ2UxHTAbBgNVBAkTFDc3IE1hc3NhY2h1c2V0
+dHMgQXZlMS4wLAYDVQQKEyVNYXNzYWNodXNldHRzIEluc3RpdHV0ZSBvZiBUZWNo
+bm9sb2d5MSowKAYDVQQLFCFJbmZvcm1hdGlvbiBTZXJ2aWNlcyAmIFRlY2hub2xv
+Z3kxFDASBgNVBAsTC1BsYXRpbnVtU1NMMRQwEgYDVQQDEwtwZ3AubWl0LmVkdTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOXCQWXwK1O/saHfUEJjeE6w
+VvTMe8xgl5qmkU+9U2TS6HdyVItD9fHZ3sAwVHo7mYtLGXp0S8F2hiiyLgQeQo84
+F/owinPaPU8c+2Ogw464HbROmjU7Vc/iHQklA0kR+lZsFwZuWd+nYjmPrNfm87Ik
+k9Wenco7wwFUquoJ8XZW1RVTr9WRWWlyNKwPnil5aBUGtbG6CP1+IFN75xfJYjz5
+g+JcLHYsKyb6JhPYxT42ZdgTPKVRJNuIpyOMXMIPB/qFgUyU+2T/g7vxoa3THllq
+vkp/ds5lpDe+uu6H9mbtMYvX5w9TBqt7YPegWcTUhGERnytXxeNpncYkzGMMUN0C
+AwEAAaOCAb8wggG7MB8GA1UdIwQYMBaAFB4Fo3ePbJbiW4dLprSGrHEADOc4MB0G
+A1UdDgQWBBRISoMA6cVQE5089wT6LFO4aiNnzTAOBgNVHQ8BAf8EBAMCBaAwDAYD
+VR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwZwYDVR0g
+BGAwXjBSBgwrBgEEAa4jAQQDAQEwQjBABggrBgEFBQcCARY0aHR0cHM6Ly93d3cu
+aW5jb21tb24ub3JnL2NlcnQvcmVwb3NpdG9yeS9jcHNfc3NsLnBkZjAIBgZngQwB
+AgIwRAYDVR0fBD0wOzA5oDegNYYzaHR0cDovL2NybC5pbmNvbW1vbi1yc2Eub3Jn
+L0luQ29tbW9uUlNBU2VydmVyQ0EuY3JsMHUGCCsGAQUFBwEBBGkwZzA+BggrBgEF
+BQcwAoYyaHR0cDovL2NydC51c2VydHJ1c3QuY29tL0luQ29tbW9uUlNBU2VydmVy
+Q0FfMi5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w
+FgYDVR0RBA8wDYILcGdwLm1pdC5lZHUwDQYJKoZIhvcNAQELBQADggEBAHbQqv2o
+LrRD8rMzaHvPHVa92gfi6bpEsiRsVw3kpH4D4k+PL9LWkgtgTWpM+MvskiUvS9ay
+FbWdXiy/peOj421fwnL/re9gmWs1g7FtUrDgIpz2T2jonPqbnIJPMHxI+ICWZMYH
+V/dO844geRKAiGs/UZbG4Uf1Jo0PxtPtD5puaUk4l9Va8WHU2OLq0kzS9K+iu/sx
+z0XG+fAMneyiXm5jtfjYE2W8/h61RhZulSUmYBkiMLzKr5eqe2VIkMqyTfyZ5zms
+1LZ1GWaouMsTBN1+2TXssQ71L1tIZg/lXJVlfVRkwOIV5Mp3ohxLSBZT8qNSef1v
+mFNa+DGU1sdl6m4=
+-----END CERTIFICATE-----
diff --git a/OpenKeychain/src/main/java/org/spongycastle/openpgp/jcajce/JcaSkipMarkerPGPObjectFactory.java b/OpenKeychain/src/main/java/org/spongycastle/openpgp/jcajce/JcaSkipMarkerPGPObjectFactory.java
new file mode 100644
index 000000000..f1cf9791a
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/spongycastle/openpgp/jcajce/JcaSkipMarkerPGPObjectFactory.java
@@ -0,0 +1,32 @@
+package org.spongycastle.openpgp.jcajce;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.spongycastle.openpgp.PGPMarker;
+
+/** This class wraps the regular PGPObjectFactory, changing its behavior to
+ * ignore all PGPMarker packets it encounters while reading. These packets
+ * carry no semantics of their own, and should be ignored according to
+ * RFC 4880.
+ *
+ * @see https://tools.ietf.org/html/rfc4880#section-5.8
+ * @see org.spongycastle.openpgp.PGPMarker
+ *
+ */
+public class JcaSkipMarkerPGPObjectFactory extends JcaPGPObjectFactory {
+
+ public JcaSkipMarkerPGPObjectFactory(InputStream in) {
+ super(in);
+ }
+
+ @Override
+ public Object nextObject() throws IOException {
+ Object o = super.nextObject();
+ while (o instanceof PGPMarker) {
+ o = super.nextObject();
+ }
+ return o;
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
index 6a9656b28..69f1862ce 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
@@ -28,6 +28,7 @@ public final class Constants {
public static final boolean DEBUG = BuildConfig.DEBUG;
public static final boolean DEBUG_LOG_DB_QUERIES = false;
+ public static final boolean DEBUG_EXPLAIN_QUERIES = false;
public static final boolean DEBUG_SYNC_REMOVE_CONTACTS = false;
public static final boolean DEBUG_KEYSERVER_SYNC = false;
@@ -40,22 +41,31 @@ public final class Constants {
public static final String CUSTOM_CONTACT_DATA_MIME_TYPE = "vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.key";
public static final String PROVIDER_AUTHORITY = BuildConfig.PROVIDER_CONTENT_AUTHORITY;
- public static final String TEMPSTORAGE_AUTHORITY = BuildConfig.APPLICATION_ID + ".tempstorage";
+ public static final String TEMP_FILE_PROVIDER_AUTHORITY = BuildConfig.APPLICATION_ID + ".tempstorage";
public static final String CLIPBOARD_LABEL = "Keychain";
- // as defined in http://tools.ietf.org/html/rfc3156, section 7
- public static final String NFC_MIME = "application/pgp-keys";
-
// as defined in http://tools.ietf.org/html/rfc3156
- // we don't use application/pgp-encrypted as it only holds the version number
- public static final String ENCRYPTED_FILES_MIME = "application/octet-stream";
- public static final String ENCRYPTED_TEXT_MIME = "text/plain";
-
- public static final String FILE_EXTENSION_PGP_MAIN = ".gpg";
- public static final String FILE_EXTENSION_PGP_ALTERNATE = ".pgp";
+ public static final String MIME_TYPE_KEYS = "application/pgp-keys";
+ // NOTE: don't use application/pgp-encrypted It only holds the version number!
+ public static final String MIME_TYPE_ENCRYPTED = "application/octet-stream";
+ // NOTE: Non-standard alternative, better use this, because application/octet-stream is too unspecific!
+ // also see https://tools.ietf.org/html/draft-bray-pgp-message-00
+ public static final String MIME_TYPE_ENCRYPTED_ALTERNATE = "application/pgp-message";
+ public static final String MIME_TYPE_TEXT = "text/plain";
+
+ public static final String FILE_EXTENSION_PGP_MAIN = ".pgp";
+ public static final String FILE_EXTENSION_PGP_ALTERNATE = ".gpg";
public static final String FILE_EXTENSION_ASC = ".asc";
+ public static final String FILE_BACKUP_PREFIX = "backup_";
+ public static final String FILE_EXTENSION_BACKUP_SECRET = ".sec.asc";
+ public static final String FILE_EXTENSION_BACKUP_PUBLIC = ".pub.asc";
+ public static final String FILE_ENCRYPTED_BACKUP_PREFIX = "backup_";
+ // actually it is ASCII Armor, so .asc would be more accurate, but Android displays a nice icon for .pgp files!
+ public static final String FILE_EXTENSION_ENCRYPTED_BACKUP_SECRET = ".sec.pgp";
+ public static final String FILE_EXTENSION_ENCRYPTED_BACKUP_PUBLIC = ".pub.pgp";
+
// used by QR Codes (Guardian Project, Monkeysphere compatiblity)
public static final String FINGERPRINT_SCHEME = "openpgp4fpr";
@@ -70,11 +80,13 @@ public final class Constants {
public static final int TEMPFILE_TTL = 24 * 60 * 60 * 1000; // 1 day
+ // the maximal length of plaintext to read in encrypt/decrypt text activities
+ public static final int TEXT_LENGTH_LIMIT = 1024 * 50;
+
public static final String SAFESLINGER_SERVER = "safeslinger-openpgp.appspot.com";
public static final class Path {
public static final File APP_DIR = new File(Environment.getExternalStorageDirectory(), "OpenKeychain");
- public static final File APP_DIR_FILE = new File(APP_DIR, "export.asc");
}
public static final class Notification {
@@ -92,7 +104,6 @@ public final class Constants {
public static final String CACHED_CONSOLIDATE = "cachedConsolidate";
public static final String SEARCH_KEYSERVER = "search_keyserver_pref";
public static final String SEARCH_KEYBASE = "search_keybase_pref";
- public static final String USE_DEFAULT_YUBIKEY_PIN = "useDefaultYubikeyPin";
public static final String USE_NUMKEYPAD_FOR_YUBIKEY_PIN = "useNumKeypadForYubikeyPin";
public static final String ENCRYPT_FILENAMES = "encryptFilenames";
public static final String FILE_USE_COMPRESSION = "useFileCompression";
@@ -142,6 +153,7 @@ public final class Constants {
public static final class key {
public static final int none = 0;
public static final int symmetric = -1;
+ public static final int backup_code = -2;
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
index 311ef2d3b..5d97dac8a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
@@ -33,7 +33,7 @@ import android.widget.Toast;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
-import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
+import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
import org.sufficientlysecure.keychain.service.KeyserverSyncAdapterService;
import org.sufficientlysecure.keychain.ui.ConsolidateDialogActivity;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
@@ -91,16 +91,18 @@ public class KeychainApplication extends Application {
}
brandGlowEffect(getApplicationContext(),
- FormattingUtils.getColorFromAttr(getApplicationContext(), R.attr.colorPrimary));
+ FormattingUtils.getColorFromAttr(getApplicationContext(), R.attr.colorPrimary));
setupAccountAsNeeded(this);
// Update keyserver list as needed
Preferences.getPreferences(this).upgradePreferences(this);
- TlsHelper.addStaticCA("pool.sks-keyservers.net", getAssets(), "sks-keyservers.netCA.cer");
+ TlsHelper.addPinnedCertificate("hkps.pool.sks-keyservers.net", getAssets(), "hkps.pool.sks-keyservers.net.CA.cer");
+ TlsHelper.addPinnedCertificate("pgp.mit.edu", getAssets(), "pgp.mit.edu.cer");
+ TlsHelper.addPinnedCertificate("api.keybase.io", getAssets(), "api.keybase.io.CA.cer");
- TemporaryStorageProvider.cleanUp(this);
+ TemporaryFileProvider.cleanUp(this);
if (!checkConsolidateRecovery()) {
// force DB upgrade, https://github.com/open-keychain/open-keychain/issues/1334
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/BitInputStream.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/BitInputStream.java
new file mode 100644
index 000000000..111e0b366
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/BitInputStream.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) Andreas Jakl
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.experimental;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * The BitInputStream allows reading individual bits from a
+ * general Java InputStream.
+ * Like the various Stream-classes from Java, the BitInputStream
+ * has to be created based on another Input stream. It provides
+ * a function to read the next bit from the stream, as well as to read multiple
+ * bits at once and write the resulting data into an integer value.
+ * <p/>
+ * source: http://developer.nokia.com/Community/Wiki/Bit_Input/Output_Stream_utility_classes_for_efficient_data_transfer
+ */
+public class BitInputStream {
+ /**
+ * The Java InputStream this class is working on.
+ */
+ private InputStream iIs;
+
+ /**
+ * The buffer containing the currently processed
+ * byte of the input stream.
+ */
+ private int iBuffer;
+
+ /**
+ * Next bit of the current byte value that the user will
+ * get. If it's 8, the next bit will be read from the
+ * next byte of the InputStream.
+ */
+ private int iNextBit = 8;
+
+ /**
+ * Create a new bit input stream based on an existing Java InputStream.
+ *
+ * @param aIs the input stream this class should read the bits from.
+ */
+ public BitInputStream(InputStream aIs) {
+ iIs = aIs;
+ }
+
+ /**
+ * Read a specified number of bits and return them combined as
+ * an integer value. The bits are written to the integer
+ * starting at the highest bit ( << aNumberOfBits ), going down
+ * to the lowest bit ( << 0 )
+ *
+ * @param aNumberOfBits defines how many bits to read from the stream.
+ * @return integer value containing the bits read from the stream.
+ * @throws IOException
+ */
+ synchronized public int readBits(final int aNumberOfBits, boolean stuffIfEnd)
+ throws IOException {
+ int value = 0;
+ for (int i = aNumberOfBits - 1; i >= 0; i--) {
+ value |= (readBit(stuffIfEnd) << i);
+ }
+ return value;
+ }
+
+ synchronized public int available() {
+ try {
+ return (8 - iNextBit) + iIs.available() * 8; // bytestream to bitstream available
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ /**
+ * Read the next bit from the stream.
+ *
+ * @return 0 if the bit is 0, 1 if the bit is 1.
+ * @throws IOException
+ */
+ synchronized public int readBit(boolean stuffIfEnd) throws IOException {
+ if (iIs == null)
+ throw new IOException("Already closed");
+
+ if (iNextBit == 8) {
+ iBuffer = iIs.read();
+
+ if (iBuffer == -1) {
+ if (stuffIfEnd) {
+ return 1;
+ } else {
+ throw new EOFException();
+ }
+ }
+
+ iNextBit = 0;
+ }
+
+ int bit = iBuffer & (1 << iNextBit);
+ iNextBit++;
+
+ bit = (bit == 0) ? 0 : 1;
+
+ return bit;
+ }
+
+ /**
+ * Close the underlying input stream.
+ *
+ * @throws IOException
+ */
+ public void close() throws IOException {
+ iIs.close();
+ iIs = null;
+ }
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/SentenceConfirm.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/SentenceConfirm.java
new file mode 100644
index 000000000..0374d878c
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/SentenceConfirm.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Jake McGinty (Open Whisper Systems)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.experimental;
+
+import android.content.Context;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * From https://github.com/mcginty/TextSecure/tree/mnemonic-poem
+ */
+public class SentenceConfirm {
+ Context context;
+ List<String> n, vi, vt, adj, adv, p, art;
+
+ public SentenceConfirm(Context context) {
+ this.context = context;
+ try {
+ n = readFile(R.raw.fp_sentence_nouns);
+ vi = readFile(R.raw.fp_sentence_verbs_i);
+ vt = readFile(R.raw.fp_sentence_verbs_t);
+ adj = readFile(R.raw.fp_sentence_adjectives);
+ adv = readFile(R.raw.fp_sentence_adverbs);
+ p = readFile(R.raw.fp_sentence_prepositions);
+ art = readFile(R.raw.fp_sentence_articles);
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "Reading sentence files failed", e);
+ }
+ }
+
+ List<String> readFile(int resId) throws IOException {
+ if (context.getApplicationContext() == null) {
+ throw new AssertionError("app context can't be null");
+ }
+
+ BufferedReader in = new BufferedReader(new InputStreamReader(
+ context.getApplicationContext()
+ .getResources()
+ .openRawResource(resId)));
+ List<String> words = new ArrayList<>();
+ String word = in.readLine();
+ while (word != null) {
+ words.add(word);
+ word = in.readLine();
+ }
+ in.close();
+ return words;
+ }
+
+ public String fromBytes(final byte[] bytes, int desiredBytes) throws IOException {
+ BitInputStream bin = new BitInputStream(new ByteArrayInputStream(bytes));
+ EntropyString fingerprint = new EntropyString();
+
+ while (fingerprint.getBits() < (desiredBytes * 8)) {
+ if (!fingerprint.isEmpty()) {
+ fingerprint.append("\n\n");
+ }
+ try {
+ fingerprint.append(getSentence(bin));
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException when creating the sentence");
+ throw e;
+ }
+ }
+ return fingerprint.toString();
+ }
+
+ /**
+ * Grab a word for a list of them using the necessary bits to choose from a BitInputStream
+ *
+ * @param words the list of words to select from
+ * @param bin the bit input stream to encode from
+ * @return A Pair of the word and the number of bits consumed from the stream
+ */
+ private EntropyString getWord(List<String> words, BitInputStream bin) throws IOException {
+ final int neededBits = log(words.size(), 2);
+ Log.d(Constants.TAG, "need: " + neededBits + " bits of entropy");
+ Log.d(Constants.TAG, "available: " + bin.available() + " bits");
+ if (neededBits > bin.available()) {
+ Log.d(Constants.TAG, "stuffed with " + (neededBits - bin.available()) + " ones!");
+ }
+ int bits = bin.readBits(neededBits, true);
+ Log.d(Constants.TAG, "got word " + words.get(bits) + " with " + neededBits + " bits of entropy");
+ return new EntropyString(words.get(bits), neededBits);
+ }
+
+ private EntropyString getNounPhrase(BitInputStream bits) throws IOException {
+ final EntropyString phrase = new EntropyString();
+ phrase.append(getWord(art, bits)).append(" ");
+ if (bits.readBit(true) != 0) {
+ phrase.append(getWord(adj, bits)).append(" ");
+ }
+ phrase.incBits();
+
+ phrase.append(getWord(n, bits));
+ Log.d(Constants.TAG, "got phrase " + phrase + " with " + phrase.getBits() + " bits of entropy");
+ return phrase;
+ }
+
+ EntropyString getSentence(BitInputStream bits) throws IOException {
+ final EntropyString sentence = new EntropyString();
+ sentence.append(getNounPhrase(bits)); // Subject
+ if (bits.readBit(true) != 0) {
+ sentence.append(" ").append(getWord(vt, bits)); // Transitive verb
+ sentence.append(" ").append(getNounPhrase(bits)); // Object of transitive verb
+ } else {
+ sentence.append(" ").append(getWord(vi, bits)); // Intransitive verb
+ }
+ sentence.incBits();
+
+ if (bits.readBit(true) != 0) {
+ sentence.append(" ").append(getWord(adv, bits)); // Adverb
+ }
+
+ sentence.incBits();
+ if (bits.readBit(true) != 0) {
+ sentence.append(" ").append(getWord(p, bits)); // Preposition
+ sentence.append(" ").append(getNounPhrase(bits)); // Object of preposition
+ }
+ sentence.incBits();
+ Log.d(Constants.TAG, "got sentence '" + sentence + "' with " + sentence.getBits() + " bits of entropy");
+
+ // uppercase first character, end with dot (without increasing the bits)
+ sentence.getBuilder().replace(0, 1,
+ Character.toString(Character.toUpperCase(sentence.getBuilder().charAt(0))));
+ sentence.getBuilder().append(".");
+
+ return sentence;
+ }
+
+ public static class EntropyString {
+ private StringBuilder builder;
+ private int bits;
+
+ public EntropyString(String phrase, int bits) {
+ this.builder = new StringBuilder(phrase);
+ this.bits = bits;
+ }
+
+ public EntropyString() {
+ this("", 0);
+ }
+
+ public StringBuilder getBuilder() {
+ return builder;
+ }
+
+ public boolean isEmpty() {
+ return builder.length() == 0;
+ }
+
+ public EntropyString append(EntropyString phrase) {
+ builder.append(phrase);
+ bits += phrase.getBits();
+ return this;
+ }
+
+ public EntropyString append(String string) {
+ builder.append(string);
+ return this;
+ }
+
+ public int getBits() {
+ return bits;
+ }
+
+ public void setBits(int bits) {
+ this.bits = bits;
+ }
+
+ public void incBits() {
+ bits += 1;
+ }
+
+ @Override
+ public String toString() {
+ return builder.toString();
+ }
+ }
+
+ private static int log(int x, int base) {
+ return (int) (Math.log(x) / Math.log(base));
+ }
+
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ExperimentalWordConfirm.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/WordConfirm.java
index 43ccac24f..daf63ea9e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ExperimentalWordConfirm.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/WordConfirm.java
@@ -15,12 +15,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-package org.sufficientlysecure.keychain.ui.util;
+package org.sufficientlysecure.keychain.experimental;
import android.content.Context;
import org.spongycastle.util.Arrays;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Log;
import java.io.BufferedReader;
@@ -29,7 +30,7 @@ import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.BitSet;
-public class ExperimentalWordConfirm {
+public class WordConfirm {
public static String getWords(Context context, byte[] fingerprintBlob) {
ArrayList<String> words = new ArrayList<>();
@@ -37,7 +38,7 @@ public class ExperimentalWordConfirm {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(
- context.getAssets().open("word_confirm_list.txt"),
+ context.getResources().openRawResource(R.raw.fp_word_list),
"UTF-8"
));
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java
index d91dd28bc..869d107ab 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java
@@ -24,6 +24,9 @@ import java.net.Proxy;
import java.util.ArrayList;
import java.util.Vector;
+import android.support.annotation.NonNull;
+
+
/**
* Search two or more types of server for online keys.
*/
@@ -31,8 +34,8 @@ public class CloudSearch {
private final static long SECONDS = 1000;
- public static ArrayList<ImportKeysListEntry> search(final String query, Preferences.CloudSearchPrefs cloudPrefs,
- final Proxy proxy)
+ public static ArrayList<ImportKeysListEntry> search(
+ @NonNull final String query, Preferences.CloudSearchPrefs cloudPrefs, @NonNull Proxy proxy)
throws Keyserver.CloudSearchFailureException {
final ArrayList<Keyserver> servers = new ArrayList<>();
@@ -40,10 +43,10 @@ public class CloudSearch {
final Vector<Keyserver.CloudSearchFailureException> problems = new Vector<>();
if (cloudPrefs.searchKeyserver) {
- servers.add(new HkpKeyserver(cloudPrefs.keyserver));
+ servers.add(new HkpKeyserver(cloudPrefs.keyserver, proxy));
}
if (cloudPrefs.searchKeybase) {
- servers.add(new KeybaseKeyserver());
+ servers.add(new KeybaseKeyserver(proxy));
}
final ImportKeysList results = new ImportKeysList(servers.size());
@@ -53,7 +56,7 @@ public class CloudSearch {
@Override
public void run() {
try {
- results.addAll(keyserver.search(query, proxy));
+ results.addAll(keyserver.search(query));
} catch (Keyserver.CloudSearchFailureException e) {
problems.add(e);
}
@@ -68,7 +71,7 @@ public class CloudSearch {
// wait for either all the searches to come back, or 10 seconds. If using proxy, wait 30 seconds.
synchronized (results) {
try {
- if (proxy != null) {
+ if (proxy == Proxy.NO_PROXY) {
results.wait(30 * SECONDS);
} else {
results.wait(10 * SECONDS);
@@ -77,7 +80,7 @@ public class CloudSearch {
// kill threads that haven't returned yet
thread.interrupt();
}
- } catch (InterruptedException e) {
+ } catch (InterruptedException ignored) {
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
index 558b8ce7d..c2190318b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
@@ -23,6 +23,7 @@ import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
+
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
@@ -45,6 +46,8 @@ import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import android.support.annotation.NonNull;
+
import de.measite.minidns.Client;
import de.measite.minidns.Question;
import de.measite.minidns.Record;
@@ -73,6 +76,7 @@ public class HkpKeyserver extends Keyserver {
private String mHost;
private short mPort;
+ private Proxy mProxy;
private boolean mSecure;
/**
@@ -149,17 +153,17 @@ public class HkpKeyserver extends Keyserver {
* connect using {@link #PORT_DEFAULT}. However, port may be specified after colon
* ("<code>hostname:port</code>", eg. "<code>p80.pool.sks-keyservers.net:80</code>").
*/
- public HkpKeyserver(String hostAndPort) {
+ public HkpKeyserver(String hostAndPort, Proxy proxy) {
String host = hostAndPort;
short port = PORT_DEFAULT;
boolean secure = false;
String[] parts = hostAndPort.split(":");
if (parts.length > 1) {
if (!parts[0].contains(".")) { // This is not a domain or ip, so it must be a protocol name
- if (parts[0].equalsIgnoreCase("hkps") || parts[0].equalsIgnoreCase("https")) {
+ if ("hkps".equalsIgnoreCase(parts[0]) || "https".equalsIgnoreCase(parts[0])) {
secure = true;
port = PORT_DEFAULT_HKPS;
- } else if (!parts[0].equalsIgnoreCase("hkp") && !parts[0].equalsIgnoreCase("http")) {
+ } else if (!"hkp".equalsIgnoreCase(parts[0]) && !"http".equalsIgnoreCase(parts[0])) {
throw new IllegalArgumentException("Protocol " + parts[0] + " is unknown");
}
host = parts[1];
@@ -176,16 +180,18 @@ public class HkpKeyserver extends Keyserver {
}
mHost = host;
mPort = port;
+ mProxy = proxy;
mSecure = secure;
}
- public HkpKeyserver(String host, short port) {
- this(host, port, false);
+ public HkpKeyserver(String host, short port, Proxy proxy) {
+ this(host, port, proxy, false);
}
- public HkpKeyserver(String host, short port, boolean secure) {
+ public HkpKeyserver(String host, short port, Proxy proxy, boolean secure) {
mHost = host;
mPort = port;
+ mProxy = proxy;
mSecure = secure;
}
@@ -196,19 +202,23 @@ public class HkpKeyserver extends Keyserver {
/**
* returns a client with pinned certificate if necessary
*
- * @param url url to be queried by client
+ * @param url url to be queried by client
* @param proxy proxy to be used by client
- * @return client with a pinned certificate if necesary
+ * @return client with a pinned certificate if necessary
*/
public static OkHttpClient getClient(URL url, Proxy proxy) throws IOException {
OkHttpClient client = new OkHttpClient();
try {
- TlsHelper.pinCertificateIfNecessary(client, url);
+ TlsHelper.usePinnedCertificateIfAvailable(client, url);
} catch (TlsHelper.TlsHelperException e) {
Log.w(Constants.TAG, e);
}
+ // don't follow any redirects
+ client.setFollowRedirects(false);
+ client.setFollowSslRedirects(false);
+
if (proxy != null) {
client.setProxy(proxy);
client.setConnectTimeout(30000, TimeUnit.MILLISECONDS);
@@ -221,14 +231,14 @@ public class HkpKeyserver extends Keyserver {
return client;
}
- private String query(String request, Proxy proxy) throws QueryFailedException, HttpError {
+ private String query(String request, @NonNull Proxy proxy) throws QueryFailedException, HttpError {
try {
URL url = new URL(getUrlPrefix() + mHost + ":" + mPort + request);
Log.d(Constants.TAG, "hkp keyserver query: " + url + " Proxy: " + proxy);
OkHttpClient client = getClient(url, proxy);
Response response = client.newCall(new Request.Builder().url(url).build()).execute();
- String responseBody = response.body().string();// contains body both in case of success or failure
+ String responseBody = response.body().string(); // contains body both in case of success or failure
if (response.isSuccessful()) {
return responseBody;
@@ -238,20 +248,15 @@ public class HkpKeyserver extends Keyserver {
} catch (IOException e) {
Log.e(Constants.TAG, "IOException at HkpKeyserver", e);
throw new QueryFailedException("Keyserver '" + mHost + "' is unavailable. Check your Internet connection!" +
- proxy == null?"":" Using proxy " + proxy);
+ (proxy == Proxy.NO_PROXY ? "" : " Using proxy " + proxy));
}
}
/**
* Results are sorted by creation date of key!
- *
- * @param query
- * @return
- * @throws QueryFailedException
- * @throws QueryNeedsRepairException
*/
@Override
- public ArrayList<ImportKeysListEntry> search(String query, Proxy proxy) throws QueryFailedException,
+ public ArrayList<ImportKeysListEntry> search(String query) throws QueryFailedException,
QueryNeedsRepairException {
ArrayList<ImportKeysListEntry> results = new ArrayList<>();
@@ -269,7 +274,7 @@ public class HkpKeyserver extends Keyserver {
String data;
try {
- data = query(request, proxy);
+ data = query(request, mProxy);
} catch (HttpError e) {
if (e.getData() != null) {
Log.d(Constants.TAG, "returned error data: " + e.getData().toLowerCase(Locale.ENGLISH));
@@ -299,30 +304,46 @@ public class HkpKeyserver extends Keyserver {
entry.setQuery(query);
entry.addOrigin(getUrlPrefix() + mHost + ":" + mPort);
- int bitSize = Integer.parseInt(matcher.group(3));
- entry.setBitStrength(bitSize);
- int algorithmId = Integer.decode(matcher.group(2));
- entry.setAlgorithm(KeyFormattingUtils.getAlgorithmInfo(algorithmId, bitSize, null));
-
// group 1 contains the full fingerprint (v4) or the long key id if available
// see https://bitbucket.org/skskeyserver/sks-keyserver/pull-request/12/fixes-for-machine-readable-indexes/diff
String fingerprintOrKeyId = matcher.group(1).toLowerCase(Locale.ENGLISH);
- if (fingerprintOrKeyId.length() > 16) {
+ if (fingerprintOrKeyId.length() == 40) {
entry.setFingerprintHex(fingerprintOrKeyId);
entry.setKeyIdHex("0x" + fingerprintOrKeyId.substring(fingerprintOrKeyId.length()
- 16, fingerprintOrKeyId.length()));
- } else {
+ } else if (fingerprintOrKeyId.length() == 16) {
// set key id only
entry.setKeyIdHex("0x" + fingerprintOrKeyId);
+ } else {
+ Log.e(Constants.TAG, "Wrong length for fingerprint/long key id.");
+ // skip this key
+ continue;
}
- final long creationDate = Long.parseLong(matcher.group(4));
- final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
- tmpGreg.setTimeInMillis(creationDate * 1000);
- entry.setDate(tmpGreg.getTime());
+ try {
+ int bitSize = Integer.parseInt(matcher.group(3));
+ entry.setBitStrength(bitSize);
+ int algorithmId = Integer.decode(matcher.group(2));
+ entry.setAlgorithm(KeyFormattingUtils.getAlgorithmInfo(algorithmId, bitSize, null));
+
+ final long creationDate = Long.parseLong(matcher.group(4));
+ final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+ tmpGreg.setTimeInMillis(creationDate * 1000);
+ entry.setDate(tmpGreg.getTime());
+ } catch (NumberFormatException e) {
+ Log.e(Constants.TAG, "Conversation for bit size, algorithm, or creation date failed.", e);
+ // skip this key
+ continue;
+ }
- entry.setRevoked(matcher.group(6).contains("r"));
- entry.setExpired(matcher.group(6).contains("e"));
+ try {
+ entry.setRevoked(matcher.group(6).contains("r"));
+ entry.setExpired(matcher.group(6).contains("e"));
+ } catch (NullPointerException e) {
+ Log.e(Constants.TAG, "Check for revocation or expiry failed.", e);
+ // skip this key
+ continue;
+ }
ArrayList<String> userIds = new ArrayList<>();
final String uidLines = matcher.group(7);
@@ -340,6 +361,10 @@ public class HkpKeyserver extends Keyserver {
tmp = URLDecoder.decode(tmp, "UTF8");
} catch (UnsupportedEncodingException ignored) {
// will never happen, because "UTF8" is supported
+ } catch (IllegalArgumentException e) {
+ Log.e(Constants.TAG, "User ID encoding broken", e);
+ // skip this user id
+ continue;
}
}
userIds.add(tmp);
@@ -353,25 +378,28 @@ public class HkpKeyserver extends Keyserver {
}
@Override
- public String get(String keyIdHex, Proxy proxy) throws QueryFailedException {
+ public String get(String keyIdHex) throws QueryFailedException {
String request = "/pks/lookup?op=get&options=mr&search=" + keyIdHex;
- Log.d(Constants.TAG, "hkp keyserver get: " + request + " using Proxy: " + proxy);
+ Log.d(Constants.TAG, "hkp keyserver get: " + request + " using Proxy: " + mProxy);
String data;
try {
- data = query(request, proxy);
+ data = query(request, mProxy);
} catch (HttpError httpError) {
Log.d(Constants.TAG, "Failed to get key at HkpKeyserver", httpError);
throw new QueryFailedException("not found");
}
+ if (data == null) {
+ throw new QueryFailedException("data is null");
+ }
Matcher matcher = PgpHelper.PGP_PUBLIC_KEY.matcher(data);
if (matcher.find()) {
return matcher.group(1);
}
- return null;
+ throw new QueryFailedException("data is null");
}
@Override
- public void add(String armoredKey, Proxy proxy) throws AddKeyException {
+ public void add(String armoredKey) throws AddKeyException {
try {
String path = "/pks/add";
String params;
@@ -382,7 +410,7 @@ public class HkpKeyserver extends Keyserver {
}
URL url = new URL(getUrlPrefix() + mHost + ":" + mPort + path);
- Log.d(Constants.TAG, "hkp keyserver add: " + url.toString());
+ Log.d(Constants.TAG, "hkp keyserver add: " + url);
Log.d(Constants.TAG, "params: " + params);
RequestBody body = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"), params);
@@ -394,7 +422,7 @@ public class HkpKeyserver extends Keyserver {
.post(body)
.build();
- Response response = getClient(url, proxy).newCall(request).execute();
+ Response response = getClient(url, mProxy).newCall(request).execute();
Log.d(Constants.TAG, "response code: " + response.code());
Log.d(Constants.TAG, "answer: " + response.body().string());
@@ -411,16 +439,15 @@ public class HkpKeyserver extends Keyserver {
@Override
public String toString() {
- return mHost + ":" + mPort;
+ return getUrlPrefix() + mHost + ":" + mPort;
}
/**
* Tries to find a server responsible for a given domain
*
* @return A responsible Keyserver or null if not found.
- * TODO: PHILIP Add proxy functionality
*/
- public static HkpKeyserver resolve(String domain) {
+ public static HkpKeyserver resolve(String domain, Proxy proxy) {
try {
Record[] records = new Client().query(new Question("_hkp._tcp." + domain, Record.TYPE.SRV)).getAnswers();
if (records.length > 0) {
@@ -435,7 +462,7 @@ public class HkpKeyserver extends Keyserver {
Record record = records[0]; // This is our best choice
if (record.getPayload().getType() == Record.TYPE.SRV) {
return new HkpKeyserver(((SRV) record.getPayload()).getName(),
- (short) ((SRV) record.getPayload()).getPort());
+ (short) ((SRV) record.getPayload()).getPort(), proxy);
}
}
} catch (Exception ignored) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
index c2865410e..e4cd6738b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
@@ -19,12 +19,13 @@ package org.sufficientlysecure.keychain.keyimport;
import com.textuality.keybase.lib.KeybaseException;
import com.textuality.keybase.lib.Match;
-import com.textuality.keybase.lib.Search;
+import com.textuality.keybase.lib.KeybaseQuery;
import com.textuality.keybase.lib.User;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.OkHttpKeybaseClient;
import java.net.Proxy;
import java.util.ArrayList;
@@ -32,10 +33,15 @@ import java.util.List;
public class KeybaseKeyserver extends Keyserver {
public static final String ORIGIN = "keybase:keybase.io";
- private String mQuery;
+
+ Proxy mProxy;
+
+ public KeybaseKeyserver(Proxy proxy) {
+ mProxy = proxy;
+ }
@Override
- public ArrayList<ImportKeysListEntry> search(String query, Proxy proxy) throws QueryFailedException,
+ public ArrayList<ImportKeysListEntry> search(String query) throws QueryFailedException,
QueryNeedsRepairException {
ArrayList<ImportKeysListEntry> results = new ArrayList<>();
@@ -46,12 +52,13 @@ public class KeybaseKeyserver extends Keyserver {
if (query.isEmpty()) {
throw new QueryTooShortException();
}
- mQuery = query;
try {
- Iterable<Match> matches = Search.search(query, proxy);
+ KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient());
+ keybaseQuery.setProxy(mProxy);
+ Iterable<Match> matches = keybaseQuery.search(query);
for (Match match : matches) {
- results.add(makeEntry(match));
+ results.add(makeEntry(match, query));
}
} catch (KeybaseException e) {
Log.e(Constants.TAG, "keybase result parsing error", e);
@@ -61,9 +68,9 @@ public class KeybaseKeyserver extends Keyserver {
return results;
}
- private ImportKeysListEntry makeEntry(Match match) throws KeybaseException {
+ private ImportKeysListEntry makeEntry(Match match, String query) throws KeybaseException {
final ImportKeysListEntry entry = new ImportKeysListEntry();
- entry.setQuery(mQuery);
+ entry.setQuery(query);
entry.addOrigin(ORIGIN);
entry.setRevoked(false); // keybase doesn’t say anything about revoked keys
@@ -99,16 +106,18 @@ public class KeybaseKeyserver extends Keyserver {
}
@Override
- public String get(String id, Proxy proxy) throws QueryFailedException {
+ public String get(String id) throws QueryFailedException {
try {
- return User.keyForUsername(id, proxy);
+ KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient());
+ keybaseQuery.setProxy(mProxy);
+ return User.keyForUsername(keybaseQuery, id);
} catch (KeybaseException e) {
throw new QueryFailedException(e.getMessage());
}
}
@Override
- public void add(String armoredKey, Proxy proxy) throws AddKeyException {
+ public void add(String armoredKey) throws AddKeyException {
throw new AddKeyException();
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
index 640b39f44..00e8d6ac5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
@@ -62,19 +62,19 @@ public abstract class Keyserver {
* query too short _or_ too many responses
*/
public static class QueryTooShortOrTooManyResponsesException extends QueryNeedsRepairException {
- private static final long serialVersionUID = 2703768928624654514L;
+ private static final long serialVersionUID = 2703768928624654518L;
}
public static class AddKeyException extends Exception {
private static final long serialVersionUID = -507574859137295530L;
}
- public abstract List<ImportKeysListEntry> search(String query, Proxy proxy) throws QueryFailedException,
- QueryNeedsRepairException;
+ public abstract List<ImportKeysListEntry> search(String query)
+ throws QueryFailedException, QueryNeedsRepairException;
- public abstract String get(String keyIdHex, Proxy proxy) throws QueryFailedException;
+ public abstract String get(String keyIdHex) throws QueryFailedException;
- public abstract void add(String armoredKey, Proxy proxy) throws AddKeyException;
+ public abstract void add(String armoredKey) throws AddKeyException;
public static String readAll(InputStream in, String encoding) throws IOException {
ByteArrayOutputStream raw = new ByteArrayOutputStream();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/linked/LinkedTokenResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/linked/LinkedTokenResource.java
index 998ec3ad4..e5a128e32 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/linked/LinkedTokenResource.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/linked/LinkedTokenResource.java
@@ -1,5 +1,7 @@
package org.sufficientlysecure.keychain.linked;
+import android.content.Context;
+
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
@@ -8,7 +10,6 @@ import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.json.JSONException;
import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.linked.resources.DnsResource;
import org.sufficientlysecure.keychain.linked.resources.GenericHttpsResource;
import org.sufficientlysecure.keychain.linked.resources.GithubResource;
import org.sufficientlysecure.keychain.linked.resources.TwitterResource;
@@ -32,8 +33,6 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import android.content.Context;
-
public abstract class LinkedTokenResource extends LinkedResource {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java
new file mode 100644
index 000000000..ae9a2c180
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BackupOperation.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.operations;
+
+
+import java.io.BufferedOutputStream;
+import java.io.DataOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import org.spongycastle.bcpg.ArmoredOutputStream;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.operations.results.ExportResult;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
+import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
+import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInputParcel;
+import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation;
+import org.sufficientlysecure.keychain.pgp.Progressable;
+import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
+import org.sufficientlysecure.keychain.service.BackupKeyringParcel;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
+import org.sufficientlysecure.keychain.util.InputData;
+import org.sufficientlysecure.keychain.util.Log;
+
+
+/**
+ * An operation class which implements high level backup
+ * operations.
+ * This class receives a source and/or destination of keys as input and performs
+ * all steps for this backup.
+ *
+ * @see org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter#getSelectedEntries()
+ * For the backup operation, the input consists of a set of key ids and
+ * either the name of a file or an output uri to write to.
+ */
+public class BackupOperation extends BaseOperation<BackupKeyringParcel> {
+
+ private static final String[] PROJECTION = new String[] {
+ KeyRings.MASTER_KEY_ID,
+ KeyRings.PUBKEY_DATA,
+ KeyRings.PRIVKEY_DATA,
+ KeyRings.HAS_ANY_SECRET
+ };
+ private static final int INDEX_MASTER_KEY_ID = 0;
+ private static final int INDEX_PUBKEY_DATA = 1;
+ private static final int INDEX_SECKEY_DATA = 2;
+ private static final int INDEX_HAS_ANY_SECRET = 3;
+
+ public BackupOperation(Context context, ProviderHelper providerHelper, Progressable
+ progressable) {
+ super(context, providerHelper, progressable);
+ }
+
+ public BackupOperation(Context context, ProviderHelper providerHelper,
+ Progressable progressable, AtomicBoolean cancelled) {
+ super(context, providerHelper, progressable, cancelled);
+ }
+
+ @NonNull
+ public ExportResult execute(@NonNull BackupKeyringParcel backupInput, @Nullable CryptoInputParcel cryptoInput) {
+
+ OperationLog log = new OperationLog();
+ if (backupInput.mMasterKeyIds != null) {
+ log.add(LogType.MSG_BACKUP, 0, backupInput.mMasterKeyIds.length);
+ } else {
+ log.add(LogType.MSG_BACKUP_ALL, 0);
+ }
+
+ try {
+
+ boolean nonEncryptedOutput = backupInput.mSymmetricPassphrase == null;
+
+ Uri backupOutputUri = nonEncryptedOutput
+ ? backupInput.mOutputUri
+ : TemporaryFileProvider.createFile(mContext);
+
+ int exportedDataSize;
+
+ { // export key data, and possibly return if we don't encrypt
+
+ DataOutputStream outStream = new DataOutputStream(new BufferedOutputStream(
+ mContext.getContentResolver().openOutputStream(backupOutputUri)));
+
+ boolean backupSuccess = exportKeysToStream(
+ log, backupInput.mMasterKeyIds, backupInput.mExportSecret, outStream);
+
+ exportedDataSize = outStream.size();
+
+ if (!backupSuccess) {
+ // if there was an error, it will be in the log so we just have to return
+ return new ExportResult(ExportResult.RESULT_ERROR, log);
+ }
+
+ if (nonEncryptedOutput) {
+ // log.add(LogType.MSG_EXPORT_NO_ENCRYPT, 1);
+ log.add(LogType.MSG_BACKUP_SUCCESS, 1);
+ return new ExportResult(ExportResult.RESULT_OK, log);
+ }
+ }
+
+ PgpSignEncryptOperation pseOp = new PgpSignEncryptOperation(mContext, mProviderHelper, mProgressable, mCancelled);
+
+ PgpSignEncryptInputParcel inputParcel = new PgpSignEncryptInputParcel();
+ inputParcel.setSymmetricPassphrase(backupInput.mSymmetricPassphrase);
+ inputParcel.setEnableAsciiArmorOutput(true);
+ inputParcel.setAddBackupHeader(true);
+
+ InputStream inStream = mContext.getContentResolver().openInputStream(backupOutputUri);
+
+ String filename;
+ if (backupInput.mMasterKeyIds != null && backupInput.mMasterKeyIds.length == 1) {
+ filename = Constants.FILE_BACKUP_PREFIX + KeyFormattingUtils.convertKeyIdToHex(backupInput.mMasterKeyIds[0]);
+ } else {
+ filename = Constants.FILE_BACKUP_PREFIX + new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
+ }
+ filename += backupInput.mExportSecret ? Constants.FILE_EXTENSION_BACKUP_SECRET : Constants.FILE_EXTENSION_BACKUP_PUBLIC;
+
+ InputData inputData = new InputData(inStream, exportedDataSize, filename);
+
+ OutputStream outStream = mContext.getContentResolver().openOutputStream(backupInput.mOutputUri);
+ outStream = new BufferedOutputStream(outStream);
+
+ PgpSignEncryptResult encryptResult = pseOp.execute(inputParcel, new CryptoInputParcel(), inputData, outStream);
+ if (!encryptResult.success()) {
+ log.addByMerge(encryptResult, 1);
+ // log.add(LogType.MSG_EXPORT_ERROR_ENCRYPT, 1);
+ return new ExportResult(ExportResult.RESULT_ERROR, log);
+ }
+
+ log.add(encryptResult, 1);
+ log.add(LogType.MSG_BACKUP_SUCCESS, 1);
+ return new ExportResult(ExportResult.RESULT_OK, log);
+
+ } catch (FileNotFoundException e) {
+ log.add(LogType.MSG_BACKUP_ERROR_URI_OPEN, 1);
+ return new ExportResult(ExportResult.RESULT_ERROR, log);
+
+ }
+
+ }
+
+ boolean exportKeysToStream(OperationLog log, long[] masterKeyIds, boolean exportSecret, OutputStream outStream) {
+
+ // noinspection unused TODO use these in a log entry
+ int okSecret = 0, okPublic = 0;
+
+ int progress = 0;
+
+ Cursor cursor = queryForKeys(masterKeyIds);
+
+ if (cursor == null || !cursor.moveToFirst()) {
+ log.add(LogType.MSG_BACKUP_ERROR_DB, 1);
+ return false; // new ExportResult(ExportResult.RESULT_ERROR, log);
+ }
+
+ try {
+
+ int numKeys = cursor.getCount();
+
+ updateProgress(mContext.getResources().getQuantityString(R.plurals.progress_exporting_key, numKeys),
+ 0, numKeys);
+
+ // For each public masterKey id
+ while (!cursor.isAfterLast()) {
+
+ long keyId = cursor.getLong(INDEX_MASTER_KEY_ID);
+ log.add(LogType.MSG_BACKUP_PUBLIC, 1, KeyFormattingUtils.beautifyKeyId(keyId));
+
+ if (writePublicKeyToStream(log, outStream, cursor)) {
+ okPublic += 1;
+
+ boolean hasSecret = cursor.getInt(INDEX_HAS_ANY_SECRET) > 0;
+ if (exportSecret && hasSecret) {
+ log.add(LogType.MSG_BACKUP_SECRET, 2, KeyFormattingUtils.beautifyKeyId(keyId));
+ if (writeSecretKeyToStream(log, outStream, cursor)) {
+ okSecret += 1;
+ }
+ }
+ }
+
+ updateProgress(progress++, numKeys);
+ cursor.moveToNext();
+ }
+
+ updateProgress(R.string.progress_done, numKeys, numKeys);
+
+ } catch (IOException e) {
+ log.add(LogType.MSG_BACKUP_ERROR_IO, 1);
+ return false; // new ExportResult(ExportResult.RESULT_ERROR, log);
+ } finally {
+ // Make sure the stream is closed
+ if (outStream != null) try {
+ outStream.close();
+ } catch (Exception e) {
+ Log.e(Constants.TAG, "error closing stream", e);
+ }
+ cursor.close();
+ }
+
+ return true;
+
+ }
+
+ private boolean writePublicKeyToStream(OperationLog log, OutputStream outStream, Cursor cursor)
+ throws IOException {
+
+ ArmoredOutputStream arOutStream = null;
+
+ try {
+ arOutStream = new ArmoredOutputStream(outStream);
+ byte[] data = cursor.getBlob(INDEX_PUBKEY_DATA);
+ CanonicalizedKeyRing ring = UncachedKeyRing.decodeFromData(data).canonicalize(log, 2, true);
+ ring.encode(arOutStream);
+
+ } catch (PgpGeneralException e) {
+ log.add(LogType.MSG_UPLOAD_ERROR_IO, 2);
+ } finally {
+ if (arOutStream != null) {
+ arOutStream.close();
+ }
+ }
+ return true;
+ }
+
+ private boolean writeSecretKeyToStream(OperationLog log, OutputStream outStream, Cursor cursor)
+ throws IOException {
+
+ ArmoredOutputStream arOutStream = null;
+
+ try {
+ arOutStream = new ArmoredOutputStream(outStream);
+ byte[] data = cursor.getBlob(INDEX_SECKEY_DATA);
+ CanonicalizedKeyRing ring = UncachedKeyRing.decodeFromData(data).canonicalize(log, 2, true);
+ ring.encode(arOutStream);
+
+ } catch (PgpGeneralException e) {
+ log.add(LogType.MSG_UPLOAD_ERROR_IO, 2);
+ } finally {
+ if (arOutStream != null) {
+ arOutStream.close();
+ }
+ }
+ return true;
+ }
+
+ private Cursor queryForKeys(long[] masterKeyIds) {
+
+ String selection = null, selectionArgs[] = null;
+
+ if (masterKeyIds != null) {
+ // convert long[] to String[]
+ selectionArgs = new String[masterKeyIds.length];
+ for (int i = 0; i < masterKeyIds.length; i++) {
+ selectionArgs[i] = Long.toString(masterKeyIds[i]);
+ }
+
+ // generates ?,?,? as placeholders for selectionArgs
+ String placeholders = TextUtils.join(",",
+ Collections.nCopies(masterKeyIds.length, "?"));
+
+ // put together selection string
+ selection = Tables.KEYS + "." + KeyRings.MASTER_KEY_ID
+ + " IN (" + placeholders + ")";
+ }
+
+ return mProviderHelper.getContentResolver().query(
+ KeyRings.buildUnifiedKeyRingsUri(), PROJECTION, selection, selectionArgs,
+ Tables.KEYS + "." + KeyRings.MASTER_KEY_ID
+ );
+
+ }
+
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java
index e4026eaaf..99d1768b1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java
@@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.operations;
import android.content.Context;
import android.os.Parcelable;
import android.support.annotation.NonNull;
+import android.support.annotation.StringRes;
import org.sufficientlysecure.keychain.Constants.key;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
@@ -81,7 +82,7 @@ public abstract class BaseOperation <T extends Parcelable> implements Passphrase
@NonNull
public abstract OperationResult execute(T input, CryptoInputParcel cryptoInput);
- public void updateProgress(int message, int current, int total) {
+ public void updateProgress(@StringRes int message, int current, int total) {
if (mProgressable != null) {
mProgressable.setProgress(message, current, total);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java
new file mode 100644
index 000000000..f6e157c74
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BenchmarkOperation.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.operations;
+
+
+import java.util.Random;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+
+import org.spongycastle.bcpg.HashAlgorithmTags;
+import org.spongycastle.bcpg.S2K;
+import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
+import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.operations.results.BenchmarkResult;
+import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
+import org.sufficientlysecure.keychain.operations.results.SignEncryptResult;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation;
+import org.sufficientlysecure.keychain.pgp.Progressable;
+import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.BenchmarkInputParcel;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.Passphrase;
+import org.sufficientlysecure.keychain.util.ProgressScaler;
+
+
+public class BenchmarkOperation extends BaseOperation<BenchmarkInputParcel> {
+
+ public BenchmarkOperation(Context context, ProviderHelper providerHelper, Progressable
+ progressable) {
+ super(context, providerHelper, progressable);
+ }
+
+ @NonNull
+ @Override
+ public BenchmarkResult execute(BenchmarkInputParcel consolidateInputParcel,
+ CryptoInputParcel cryptoInputParcel) {
+ OperationLog log = new OperationLog();
+ log.add(LogType.MSG_BENCH, 0);
+
+ // random data
+ byte[] buf = new byte[1024*1024*5];
+ new Random().nextBytes(buf);
+
+ Passphrase passphrase = new Passphrase("a");
+
+ int numRepeats = 5;
+ long totalTime = 0;
+
+ // encrypt
+ SignEncryptResult encryptResult;
+ int i = 0;
+ do {
+ SignEncryptOperation op =
+ new SignEncryptOperation(mContext, mProviderHelper,
+ new ProgressScaler(mProgressable, i*(50/numRepeats), (i+1)*(50/numRepeats), 100), mCancelled);
+ SignEncryptParcel input = new SignEncryptParcel();
+ input.setSymmetricPassphrase(passphrase);
+ input.setBytes(buf);
+ encryptResult = op.execute(input, new CryptoInputParcel());
+ log.add(encryptResult, 1);
+ log.add(LogType.MSG_BENCH_ENC_TIME, 2,
+ String.format("%.2f", encryptResult.getResults().get(0).mOperationTime / 1000.0));
+ totalTime += encryptResult.getResults().get(0).mOperationTime;
+ } while (++i < numRepeats);
+
+ long encryptionTime = totalTime / numRepeats;
+ totalTime = 0;
+
+ // decrypt
+ i = 0;
+ do {
+ DecryptVerifyResult decryptResult;
+ PgpDecryptVerifyOperation op =
+ new PgpDecryptVerifyOperation(mContext, mProviderHelper,
+ new ProgressScaler(mProgressable, 50 +i*(50/numRepeats), 50 +(i+1)*(50/numRepeats), 100));
+ PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(encryptResult.getResultBytes());
+ input.setAllowSymmetricDecryption(true);
+ decryptResult = op.execute(input, new CryptoInputParcel(passphrase));
+ log.add(decryptResult, 1);
+ log.add(LogType.MSG_BENCH_DEC_TIME, 2, String.format("%.2f", decryptResult.mOperationTime / 1000.0));
+ totalTime += decryptResult.mOperationTime;
+ } while (++i < numRepeats);
+
+ long decryptionTime = totalTime / numRepeats;
+ totalTime = 0;
+
+ int iterationsFor100ms;
+ try {
+ PGPDigestCalculatorProvider digestCalcProvider = new JcaPGPDigestCalculatorProviderBuilder()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build();
+ PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder(
+ digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
+ "".toCharArray());
+
+ byte[] iv = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
+ int iterations = 0;
+ while (iterations < 255 && totalTime < 100) {
+ iterations += 1;
+
+ S2K s2k = new S2K(HashAlgorithmTags.SHA1, iv, iterations);
+ totalTime = System.currentTimeMillis();
+ decryptorFactory.makeKeyFromPassPhrase(SymmetricKeyAlgorithmTags.AES_128, s2k);
+ totalTime = System.currentTimeMillis() -totalTime;
+
+ if ((iterations % 10) == 0) {
+ log.add(LogType.MSG_BENCH_S2K_FOR_IT, 1, Integer.toString(iterations), Long.toString(totalTime));
+ }
+
+ }
+ iterationsFor100ms = iterations;
+
+ } catch (PGPException e) {
+ Log.e(Constants.TAG, "internal error during benchmark", e);
+ log.add(LogType.MSG_INTERNAL_ERROR, 0);
+ return new BenchmarkResult(BenchmarkResult.RESULT_ERROR, log);
+ }
+
+ log.add(LogType.MSG_BENCH_S2K_100MS_ITS, 1, Integer.toString(iterationsFor100ms));
+ log.add(LogType.MSG_BENCH_ENC_TIME_AVG, 1, String.format("%.2f", encryptionTime/1000.0));
+ log.add(LogType.MSG_BENCH_DEC_TIME_AVG, 1, String.format("%.2f", decryptionTime/1000.0));
+
+ log.add(LogType.MSG_BENCH_SUCCESS, 0);
+ return new BenchmarkResult(BenchmarkResult.RESULT_OK, log);
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
index eeed24db0..7d11fa1f1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
@@ -17,15 +17,20 @@
package org.sufficientlysecure.keychain.operations;
+
+import java.net.Proxy;
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import android.content.Context;
import android.support.annotation.NonNull;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
-import org.sufficientlysecure.keychain.operations.results.ExportResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
+import org.sufficientlysecure.keychain.operations.results.UploadResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
@@ -40,6 +45,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
+import org.sufficientlysecure.keychain.service.UploadKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder;
@@ -48,10 +54,6 @@ import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.Preferences;
import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
-import java.net.Proxy;
-import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicBoolean;
-
/**
* An operation which implements a high level user id certification operation.
* <p/>
@@ -204,23 +206,9 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
}
// these variables are used inside the following loop, but they need to be created only once
- HkpKeyserver keyServer = null;
- ExportOperation exportOperation = null;
- Proxy proxy = null;
+ UploadOperation uploadOperation = null;
if (parcel.keyServerUri != null) {
- keyServer = new HkpKeyserver(parcel.keyServerUri);
- exportOperation = new ExportOperation(mContext, mProviderHelper, mProgressable);
- if (cryptoInput.getParcelableProxy() == null) {
- // explicit proxy not set
- if (!OrbotHelper.isOrbotInRequiredState(mContext)) {
- return new CertifyResult(null,
- RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput);
- }
- proxy = Preferences.getPreferences(mContext).getProxyPrefs()
- .parcelableProxy.getProxy();
- } else {
- proxy = cryptoInput.getParcelableProxy().getProxy();
- }
+ uploadOperation = new UploadOperation(mContext, mProviderHelper, mProgressable, mCancelled);
}
// Write all certified keys into the database
@@ -239,11 +227,10 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
mProviderHelper.clearLog();
SaveKeyringResult result = mProviderHelper.savePublicKeyRing(certifiedKey);
- if (exportOperation != null) {
- ExportResult uploadResult = exportOperation.uploadKeyRingToServer(
- keyServer,
- certifiedKey,
- proxy);
+ if (uploadOperation != null) {
+ UploadKeyringParcel uploadInput =
+ new UploadKeyringParcel(parcel.keyServerUri, certifiedKey.getMasterKeyId());
+ UploadResult uploadResult = uploadOperation.execute(uploadInput, cryptoInput);
log.add(uploadResult, 2);
if (uploadResult.success()) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java
index f5ba88502..3b2c484be 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java
@@ -17,17 +17,20 @@
package org.sufficientlysecure.keychain.operations;
+
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import android.content.Context;
import android.support.annotation.NonNull;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
-import org.sufficientlysecure.keychain.operations.results.ExportResult;
-import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
+import org.sufficientlysecure.keychain.operations.results.UploadResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.Progressable;
@@ -35,17 +38,14 @@ import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
-import org.sufficientlysecure.keychain.service.ExportKeyringParcel;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.service.UploadKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.ProgressScaler;
-import java.io.IOException;
-import java.util.concurrent.atomic.AtomicBoolean;
-
/**
* An operation which implements a high level key edit operation.
* <p/>
@@ -72,7 +72,7 @@ public class EditKeyOperation extends BaseOperation<SaveKeyringParcel> {
* @return the result of the operation
*/
@NonNull
- public InputPendingResult execute(SaveKeyringParcel saveParcel, CryptoInputParcel cryptoInput) {
+ public EditKeyResult execute(SaveKeyringParcel saveParcel, CryptoInputParcel cryptoInput) {
OperationLog log = new OperationLog();
log.add(LogType.MSG_ED, 0);
@@ -99,7 +99,8 @@ public class EditKeyOperation extends BaseOperation<SaveKeyringParcel> {
modifyResult = keyOperations.modifySecretKeyRing(secRing, cryptoInput, saveParcel);
if (modifyResult.isPending()) {
- return modifyResult;
+ log.add(modifyResult, 1);
+ return new EditKeyResult(log, modifyResult);
}
} catch (NotFoundException e) {
@@ -134,32 +135,29 @@ public class EditKeyOperation extends BaseOperation<SaveKeyringParcel> {
UncachedKeyRing ring = modifyResult.getRing();
if (saveParcel.isUpload()) {
- UncachedKeyRing publicKeyRing;
+ byte[] keyringBytes;
try {
- publicKeyRing = ring.extractPublicKeyRing();
+ UncachedKeyRing publicKeyRing = ring.extractPublicKeyRing();
+ keyringBytes = publicKeyRing.getEncoded();
} catch (IOException e) {
log.add(LogType.MSG_ED_ERROR_EXTRACTING_PUBLIC_UPLOAD, 1);
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
}
- ExportKeyringParcel exportKeyringParcel =
- new ExportKeyringParcel(saveParcel.getUploadKeyserver(),
- publicKeyRing);
+ UploadKeyringParcel exportKeyringParcel =
+ new UploadKeyringParcel(saveParcel.getUploadKeyserver(), keyringBytes);
- ExportResult uploadResult =
- new ExportOperation(mContext, mProviderHelper, mProgressable)
+ UploadResult uploadResult =
+ new UploadOperation(mContext, mProviderHelper, mProgressable, mCancelled)
.execute(exportKeyringParcel, cryptoInput);
+ log.add(uploadResult, 2);
+
if (uploadResult.isPending()) {
- return uploadResult;
+ return new EditKeyResult(log, uploadResult);
} else if (!uploadResult.success() && saveParcel.isUploadAtomic()) {
// if atomic, update fail implies edit operation should also fail and not save
- log.add(uploadResult, 2);
- return new EditKeyResult(log, RequiredInputParcel.createRetryUploadOperation(),
- cryptoInput);
- } else {
- // upload succeeded or not atomic so we continue
- log.add(uploadResult, 2);
+ return new EditKeyResult(log, RequiredInputParcel.createRetryUploadOperation(), cryptoInput);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java
deleted file mode 100644
index 531ac01f2..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ExportOperation.java
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
- * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.operations;
-
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.Proxy;
-import java.util.Collections;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-
-import org.spongycastle.bcpg.ArmoredOutputStream;
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
-import org.sufficientlysecure.keychain.keyimport.Keyserver.AddKeyException;
-import org.sufficientlysecure.keychain.operations.results.ExportResult;
-import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
-import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
-import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
-import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
-import org.sufficientlysecure.keychain.pgp.Progressable;
-import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
-import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.ExportKeyringParcel;
-import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
-import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
-import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
-import org.sufficientlysecure.keychain.util.FileHelper;
-import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.Preferences;
-import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
-
-/**
- * An operation class which implements high level export
- * operations.
- * This class receives a source and/or destination of keys as input and performs
- * all steps for this export.
- *
- * @see org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter#getSelectedEntries()
- * For the export operation, the input consists of a set of key ids and
- * either the name of a file or an output uri to write to.
- */
-public class ExportOperation extends BaseOperation<ExportKeyringParcel> {
-
- public ExportOperation(Context context, ProviderHelper providerHelper, Progressable
- progressable) {
- super(context, providerHelper, progressable);
- }
-
- public ExportOperation(Context context, ProviderHelper providerHelper,
- Progressable progressable, AtomicBoolean cancelled) {
- super(context, providerHelper, progressable, cancelled);
- }
-
- public ExportResult uploadKeyRingToServer(HkpKeyserver server, CanonicalizedPublicKeyRing keyring,
- Proxy proxy) {
- return uploadKeyRingToServer(server, keyring.getUncachedKeyRing(), proxy);
- }
-
- public ExportResult uploadKeyRingToServer(HkpKeyserver server, UncachedKeyRing keyring, Proxy proxy) {
- mProgressable.setProgress(R.string.progress_uploading, 0, 1);
-
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- ArmoredOutputStream aos = null;
- OperationLog log = new OperationLog();
- log.add(LogType.MSG_EXPORT_UPLOAD_PUBLIC, 0, KeyFormattingUtils.convertKeyIdToHex(
- keyring.getPublicKey().getKeyId()
- ));
-
- try {
- aos = new ArmoredOutputStream(bos);
- keyring.encode(aos);
- aos.close();
-
- String armoredKey = bos.toString("UTF-8");
- server.add(armoredKey, proxy);
-
- log.add(LogType.MSG_EXPORT_UPLOAD_SUCCESS, 1);
- return new ExportResult(ExportResult.RESULT_OK, log);
- } catch (IOException e) {
- Log.e(Constants.TAG, "IOException", e);
-
- log.add(LogType.MSG_EXPORT_ERROR_KEY, 1);
- return new ExportResult(ExportResult.RESULT_ERROR, log);
- } catch (AddKeyException e) {
- Log.e(Constants.TAG, "AddKeyException", e);
-
- log.add(LogType.MSG_EXPORT_ERROR_UPLOAD, 1);
- return new ExportResult(ExportResult.RESULT_ERROR, log);
- } finally {
- mProgressable.setProgress(R.string.progress_uploading, 1, 1);
- try {
- if (aos != null) {
- aos.close();
- }
- bos.close();
- } catch (IOException e) {
- // this is just a finally thing, no matter if it doesn't work out.
- }
- }
- }
-
- public ExportResult exportToFile(long[] masterKeyIds, boolean exportSecret, String outputFile) {
-
- OperationLog log = new OperationLog();
- if (masterKeyIds != null) {
- log.add(LogType.MSG_EXPORT, 0, masterKeyIds.length);
- } else {
- log.add(LogType.MSG_EXPORT_ALL, 0);
- }
-
- // do we have a file name?
- if (outputFile == null) {
- log.add(LogType.MSG_EXPORT_ERROR_NO_FILE, 1);
- return new ExportResult(ExportResult.RESULT_ERROR, log);
- }
-
- log.add(LogType.MSG_EXPORT_FILE_NAME, 1, outputFile);
-
- // check if storage is ready
- if (!FileHelper.isStorageMounted(outputFile)) {
- log.add(LogType.MSG_EXPORT_ERROR_STORAGE, 1);
- return new ExportResult(ExportResult.RESULT_ERROR, log);
- }
-
- try {
- OutputStream outStream = new FileOutputStream(outputFile);
- try {
- ExportResult result = exportKeyRings(log, masterKeyIds, exportSecret, outStream);
- if (result.cancelled()) {
- //noinspection ResultOfMethodCallIgnored
- new File(outputFile).delete();
- }
- return result;
- } finally {
- outStream.close();
- }
- } catch (IOException e) {
- log.add(LogType.MSG_EXPORT_ERROR_FOPEN, 1);
- return new ExportResult(ExportResult.RESULT_ERROR, log);
- }
-
- }
-
- public ExportResult exportToUri(long[] masterKeyIds, boolean exportSecret, Uri outputUri) {
-
- OperationLog log = new OperationLog();
- if (masterKeyIds != null) {
- log.add(LogType.MSG_EXPORT, 0, masterKeyIds.length);
- } else {
- log.add(LogType.MSG_EXPORT_ALL, 0);
- }
-
- // do we have a file name?
- if (outputUri == null) {
- log.add(LogType.MSG_EXPORT_ERROR_NO_URI, 1);
- return new ExportResult(ExportResult.RESULT_ERROR, log);
- }
-
- try {
- OutputStream outStream = mProviderHelper.getContentResolver().openOutputStream
- (outputUri);
- return exportKeyRings(log, masterKeyIds, exportSecret, outStream);
- } catch (FileNotFoundException e) {
- log.add(LogType.MSG_EXPORT_ERROR_URI_OPEN, 1);
- return new ExportResult(ExportResult.RESULT_ERROR, log);
- }
-
- }
-
- ExportResult exportKeyRings(OperationLog log, long[] masterKeyIds, boolean exportSecret,
- OutputStream outStream) {
-
- /* TODO isn't this checked above, with the isStorageMounted call?
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- log.add(LogType.MSG_EXPORT_ERROR_STORAGE, 1);
- return new ExportResult(ExportResult.RESULT_ERROR, log);
- }
- */
-
- if (!BufferedOutputStream.class.isInstance(outStream)) {
- outStream = new BufferedOutputStream(outStream);
- }
-
- int okSecret = 0, okPublic = 0, progress = 0;
-
- Cursor cursor = null;
- try {
-
- String selection = null, selectionArgs[] = null;
-
- if (masterKeyIds != null) {
- // convert long[] to String[]
- selectionArgs = new String[masterKeyIds.length];
- for (int i = 0; i < masterKeyIds.length; i++) {
- selectionArgs[i] = Long.toString(masterKeyIds[i]);
- }
-
- // generates ?,?,? as placeholders for selectionArgs
- String placeholders = TextUtils.join(",",
- Collections.nCopies(masterKeyIds.length, "?"));
-
- // put together selection string
- selection = Tables.KEYS + "." + KeyRings.MASTER_KEY_ID
- + " IN (" + placeholders + ")";
- }
-
- cursor = mProviderHelper.getContentResolver().query(
- KeyRings.buildUnifiedKeyRingsUri(), new String[]{
- KeyRings.MASTER_KEY_ID, KeyRings.PUBKEY_DATA,
- KeyRings.PRIVKEY_DATA, KeyRings.HAS_ANY_SECRET
- }, selection, selectionArgs, Tables.KEYS + "." + KeyRings.MASTER_KEY_ID
- );
-
- if (cursor == null || !cursor.moveToFirst()) {
- log.add(LogType.MSG_EXPORT_ERROR_DB, 1);
- return new ExportResult(ExportResult.RESULT_ERROR, log, okPublic, okSecret);
- }
-
- int numKeys = cursor.getCount();
-
- updateProgress(
- mContext.getResources().getQuantityString(R.plurals.progress_exporting_key,
- numKeys), 0, numKeys);
-
- // For each public masterKey id
- while (!cursor.isAfterLast()) {
-
- long keyId = cursor.getLong(0);
- ArmoredOutputStream arOutStream = null;
-
- // Create an output stream
- try {
- arOutStream = new ArmoredOutputStream(outStream);
-
- log.add(LogType.MSG_EXPORT_PUBLIC, 1, KeyFormattingUtils.beautifyKeyId(keyId));
-
- byte[] data = cursor.getBlob(1);
- CanonicalizedKeyRing ring =
- UncachedKeyRing.decodeFromData(data).canonicalize(log, 2, true);
- ring.encode(arOutStream);
-
- okPublic += 1;
- } catch (PgpGeneralException e) {
- log.add(LogType.MSG_EXPORT_ERROR_KEY, 2);
- updateProgress(progress++, numKeys);
- continue;
- } finally {
- // make sure this is closed
- if (arOutStream != null) {
- arOutStream.close();
- }
- arOutStream = null;
- }
-
- if (exportSecret && cursor.getInt(3) > 0) {
- try {
- arOutStream = new ArmoredOutputStream(outStream);
-
- // export secret key part
- log.add(LogType.MSG_EXPORT_SECRET, 2, KeyFormattingUtils.beautifyKeyId
- (keyId));
- byte[] data = cursor.getBlob(2);
- CanonicalizedKeyRing ring =
- UncachedKeyRing.decodeFromData(data).canonicalize(log, 2, true);
- ring.encode(arOutStream);
-
- okSecret += 1;
- } catch (PgpGeneralException e) {
- log.add(LogType.MSG_EXPORT_ERROR_KEY, 2);
- updateProgress(progress++, numKeys);
- continue;
- } finally {
- // make sure this is closed
- if (arOutStream != null) {
- arOutStream.close();
- }
- }
- }
-
- updateProgress(progress++, numKeys);
-
- cursor.moveToNext();
- }
-
- updateProgress(R.string.progress_done, numKeys, numKeys);
-
- } catch (IOException e) {
- log.add(LogType.MSG_EXPORT_ERROR_IO, 1);
- return new ExportResult(ExportResult.RESULT_ERROR, log, okPublic, okSecret);
- } finally {
- // Make sure the stream is closed
- if (outStream != null) try {
- outStream.close();
- } catch (Exception e) {
- Log.e(Constants.TAG, "error closing stream", e);
- }
- if (cursor != null) {
- cursor.close();
- }
- }
-
-
- log.add(LogType.MSG_EXPORT_SUCCESS, 1);
- return new ExportResult(ExportResult.RESULT_OK, log, okPublic, okSecret);
-
- }
-
- @NonNull
- public ExportResult execute(ExportKeyringParcel exportInput, CryptoInputParcel cryptoInput) {
- switch (exportInput.mExportType) {
- case UPLOAD_KEYSERVER: {
- Proxy proxy;
- if (cryptoInput.getParcelableProxy() == null) {
- // explicit proxy not set
- if (!OrbotHelper.isOrbotInRequiredState(mContext)) {
- return new ExportResult(null,
- RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput);
- }
- proxy = Preferences.getPreferences(mContext).getProxyPrefs()
- .parcelableProxy.getProxy();
- } else {
- proxy = cryptoInput.getParcelableProxy().getProxy();
- }
-
- HkpKeyserver hkpKeyserver = new HkpKeyserver(exportInput.mKeyserver);
- try {
- if (exportInput.mCanonicalizedPublicKeyringUri != null) {
- CanonicalizedPublicKeyRing keyring
- = mProviderHelper.getCanonicalizedPublicKeyRing(
- exportInput.mCanonicalizedPublicKeyringUri);
- return uploadKeyRingToServer(hkpKeyserver, keyring, proxy);
- } else {
- return uploadKeyRingToServer(hkpKeyserver, exportInput.mUncachedKeyRing,
- proxy);
- }
- } catch (ProviderHelper.NotFoundException e) {
- Log.e(Constants.TAG, "error uploading key", e);
- return new ExportResult(ExportResult.RESULT_ERROR, new OperationLog());
- }
- }
- case EXPORT_FILE: {
- return exportToFile(exportInput.mMasterKeyIds, exportInput.mExportSecret,
- exportInput.mOutputFile);
- }
- case EXPORT_URI: {
- return exportToUri(exportInput.mMasterKeyIds, exportInput.mExportSecret,
- exportInput.mOutputUri);
- }
- default: { // can never happen, all enum types must be handled above
- throw new AssertionError("must not happen, this is a bug!");
- }
- }
- }
-} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java
index 89575338f..19a05790f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java
@@ -28,7 +28,7 @@ import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -82,6 +82,8 @@ import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
*/
public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
+ public static final int MAX_THREADS = 10;
+
public ImportOperation(Context context, ProviderHelper providerHelper, Progressable
progressable) {
super(context, providerHelper, progressable);
@@ -133,7 +135,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
@NonNull
private ImportKeyResult serialKeyRingImport(Iterator<ParcelableKeyRing> entries, int num,
String keyServerUri, Progressable progressable,
- Proxy proxy) {
+ @NonNull Proxy proxy) {
if (progressable != null) {
progressable.setProgress(R.string.progress_importing, 0, 100);
}
@@ -188,7 +190,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
// Make sure we have the keyserver instance cached
if (keyServer == null) {
log.add(LogType.MSG_IMPORT_KEYSERVER, 1, keyServerUri);
- keyServer = new HkpKeyserver(keyServerUri);
+ keyServer = new HkpKeyserver(keyServerUri, proxy);
}
try {
@@ -197,11 +199,10 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
if (entry.mExpectedFingerprint != null) {
log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, "0x" +
entry.mExpectedFingerprint.substring(24));
- data = keyServer.get("0x" + entry.mExpectedFingerprint, proxy)
- .getBytes();
+ data = keyServer.get("0x" + entry.mExpectedFingerprint).getBytes();
} else {
log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, entry.mKeyIdHex);
- data = keyServer.get(entry.mKeyIdHex, proxy).getBytes();
+ data = keyServer.get(entry.mKeyIdHex).getBytes();
}
key = UncachedKeyRing.decodeFromData(data);
if (key != null) {
@@ -219,12 +220,12 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
if (entry.mKeybaseName != null) {
// Make sure we have this cached
if (keybaseServer == null) {
- keybaseServer = new KeybaseKeyserver();
+ keybaseServer = new KeybaseKeyserver(proxy);
}
try {
log.add(LogType.MSG_IMPORT_FETCH_KEYBASE, 2, entry.mKeybaseName);
- byte[] data = keybaseServer.get(entry.mKeybaseName, proxy).getBytes();
+ byte[] data = keybaseServer.get(entry.mKeybaseName).getBytes();
UncachedKeyRing keybaseKey = UncachedKeyRing.decodeFromData(data);
// If there already is a key, merge the two
@@ -261,12 +262,6 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
continue;
}
- // Another check if we have been cancelled
- if (checkCancelled()) {
- cancelled = true;
- break;
- }
-
SaveKeyringResult result;
// synchronizing prevents https://github.com/open-keychain/open-keychain/issues/1221
// and https://github.com/open-keychain/open-keychain/issues/1480
@@ -365,13 +360,15 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
}
}
- // Final log entry, it's easier to do this individually
- if ((newKeys > 0 || updatedKeys > 0) && badKeys > 0) {
- log.add(LogType.MSG_IMPORT_PARTIAL, 1);
- } else if (newKeys > 0 || updatedKeys > 0) {
- log.add(LogType.MSG_IMPORT_SUCCESS, 1);
- } else {
- log.add(LogType.MSG_IMPORT_ERROR, 1);
+ if (!cancelled) {
+ // Final log entry, it's easier to do this individually
+ if ((newKeys > 0 || updatedKeys > 0) && badKeys > 0) {
+ log.add(LogType.MSG_IMPORT_PARTIAL, 1);
+ } else if (newKeys > 0 || updatedKeys > 0) {
+ log.add(LogType.MSG_IMPORT_SUCCESS, 1);
+ } else {
+ log.add(LogType.MSG_IMPORT_ERROR, 1);
+ }
}
return new ImportKeyResult(resultType, log, newKeys, updatedKeys, badKeys, secret,
@@ -400,8 +397,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
return new ImportKeyResult(null,
RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput);
}
- proxy = Preferences.getPreferences(mContext).getProxyPrefs().parcelableProxy
- .getProxy();
+ proxy = Preferences.getPreferences(mContext).getProxyPrefs().getProxy();
} else {
proxy = cryptoInput.getParcelableProxy().getProxy();
}
@@ -414,62 +410,61 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
}
@NonNull
- private ImportKeyResult multiThreadedKeyImport(Iterator<ParcelableKeyRing> keyListIterator,
+ private ImportKeyResult multiThreadedKeyImport(@NonNull Iterator<ParcelableKeyRing> keyListIterator,
int totKeys, final String keyServer,
final Proxy proxy) {
Log.d(Constants.TAG, "Multi-threaded key import starting");
- if (keyListIterator != null) {
- KeyImportAccumulator accumulator = new KeyImportAccumulator(totKeys, mProgressable);
-
- final ProgressScaler ignoreProgressable = new ProgressScaler();
+ KeyImportAccumulator accumulator = new KeyImportAccumulator(totKeys, mProgressable);
- final int maxThreads = 200;
- ExecutorService importExecutor = new ThreadPoolExecutor(0, maxThreads,
- 30L, TimeUnit.SECONDS,
- new SynchronousQueue<Runnable>());
+ final ProgressScaler ignoreProgressable = new ProgressScaler();
- ExecutorCompletionService<ImportKeyResult> importCompletionService =
- new ExecutorCompletionService<>(importExecutor);
+ ExecutorService importExecutor = new ThreadPoolExecutor(0, MAX_THREADS, 30L, TimeUnit.SECONDS,
+ new LinkedBlockingQueue<Runnable>());
- while (keyListIterator.hasNext()) { // submit all key rings to be imported
+ ExecutorCompletionService<ImportKeyResult> importCompletionService =
+ new ExecutorCompletionService<>(importExecutor);
- final ParcelableKeyRing pkRing = keyListIterator.next();
+ while (keyListIterator.hasNext()) { // submit all key rings to be imported
- Callable<ImportKeyResult> importOperationCallable = new Callable<ImportKeyResult>
- () {
+ final ParcelableKeyRing pkRing = keyListIterator.next();
- @Override
- public ImportKeyResult call() {
+ Callable<ImportKeyResult> importOperationCallable = new Callable<ImportKeyResult>
+ () {
- ArrayList<ParcelableKeyRing> list = new ArrayList<>();
- list.add(pkRing);
+ @Override
+ public ImportKeyResult call() {
- return serialKeyRingImport(list.iterator(), 1, keyServer,
- ignoreProgressable, proxy);
+ if (checkCancelled()) {
+ return null;
}
- };
- importCompletionService.submit(importOperationCallable);
- }
+ ArrayList<ParcelableKeyRing> list = new ArrayList<>();
+ list.add(pkRing);
- while (!accumulator.isImportFinished()) { // accumulate the results of each import
- try {
- accumulator.accumulateKeyImport(importCompletionService.take().get());
- } catch (InterruptedException | ExecutionException e) {
- Log.e(Constants.TAG, "A key could not be imported during multi-threaded " +
- "import", e);
- // do nothing?
- if (e instanceof ExecutionException) {
- // Since serialKeyRingImport does not throw any exceptions, this is what
- // would have happened if
- // we were importing the key on this thread
- throw new RuntimeException();
- }
+ return serialKeyRingImport(list.iterator(), 1, keyServer, ignoreProgressable, proxy);
+ }
+ };
+
+ importCompletionService.submit(importOperationCallable);
+ }
+
+ while (!accumulator.isImportFinished()) { // accumulate the results of each import
+ try {
+ accumulator.accumulateKeyImport(importCompletionService.take().get());
+ } catch (InterruptedException | ExecutionException e) {
+ Log.e(Constants.TAG, "A key could not be imported during multi-threaded " +
+ "import", e);
+ // do nothing?
+ if (e instanceof ExecutionException) {
+ // Since serialKeyRingImport does not throw any exceptions, this is what
+ // would have happened if
+ // we were importing the key on this thread
+ throw new RuntimeException();
}
}
- return accumulator.getConsolidatedResult();
}
- return new ImportKeyResult(ImportKeyResult.RESULT_FAIL_NOTHING, new OperationLog());
+ return accumulator.getConsolidatedResult();
+
}
/**
@@ -486,6 +481,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
private int mUpdatedKeys = 0;
private int mSecret = 0;
private int mResultType = 0;
+ private boolean mHasCancelledResult;
/**
* Accumulates keyring imports and updates the progressable whenever a new key is imported.
@@ -503,14 +499,25 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
}
}
- public synchronized void accumulateKeyImport(ImportKeyResult result) {
+ public void accumulateKeyImport(ImportKeyResult result) {
mImportedKeys++;
+ if (result == null) {
+ return;
+ }
+
if (mProgressable != null) {
mProgressable.setProgress(mImportedKeys, mTotalKeys);
}
- mImportLog.addAll(result.getLog().toList());//accumulates log
+ boolean notCancelledOrFirstCancelled = !result.cancelled() || !mHasCancelledResult;
+ if (notCancelledOrFirstCancelled) {
+ mImportLog.addAll(result.getLog().toList()); //accumulates log
+ if (result.cancelled()) {
+ mHasCancelledResult = true;
+ }
+ }
+
mBadKeys += result.mBadKeys;
mNewKeys += result.mNewKeys;
mUpdatedKeys += result.mUpdatedKeys;
@@ -533,7 +540,9 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
// adding required information to mResultType
// special case,no keys requested for import
- if (mBadKeys == 0 && mNewKeys == 0 && mUpdatedKeys == 0) {
+ if (mBadKeys == 0 && mNewKeys == 0 && mUpdatedKeys == 0
+ && (mResultType & ImportKeyResult.RESULT_CANCELLED)
+ != ImportKeyResult.RESULT_CANCELLED) {
mResultType = ImportKeyResult.RESULT_FAIL_NOTHING;
} else {
if (mNewKeys > 0) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java
index 9170dc139..bb8d6ad73 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java
@@ -25,9 +25,12 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
+import android.content.ClipDescription;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
+import android.text.TextUtils;
+import android.webkit.MimeTypeMap;
import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.codec.DecodeMonitor;
@@ -47,7 +50,7 @@ import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
+import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
import org.sufficientlysecure.keychain.service.InputDataParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
@@ -100,32 +103,40 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> {
decryptInput.setInputUri(input.getInputUri());
- currentInputUri = TemporaryStorageProvider.createFile(mContext);
+ currentInputUri = TemporaryFileProvider.createFile(mContext);
decryptInput.setOutputUri(currentInputUri);
decryptResult = op.execute(decryptInput, cryptoInput);
if (decryptResult.isPending()) {
return new InputDataResult(log, decryptResult);
}
- log.addByMerge(decryptResult, 2);
+ log.addByMerge(decryptResult, 1);
- if (!decryptResult.success()) {
- log.add(LogType.MSG_DATA_ERROR_OPENPGP, 1);
+ if ( ! decryptResult.success()) {
return new InputDataResult(InputDataResult.RESULT_ERROR, log);
}
+ // inform the storage provider about the mime type for this uri
+ if (decryptResult.getDecryptionMetadata() != null) {
+ TemporaryFileProvider.setMimeType(mContext, currentInputUri,
+ decryptResult.getDecryptionMetadata().getMimeType());
+ }
+
} else {
currentInputUri = input.getInputUri();
}
- // don't even attempt if we know the data isn't suitable for mime content
+ // don't even attempt if we know the data isn't suitable for mime content, or if we have a filename
boolean skipMimeParsing = false;
if (decryptResult != null && decryptResult.getDecryptionMetadata() != null) {
- String contentType = decryptResult.getDecryptionMetadata().getMimeType();
- if (contentType != null
- && !contentType.startsWith("multipart/")
- && !contentType.startsWith("text/")
- && !contentType.startsWith("application/")) {
+ OpenPgpMetadata metadata = decryptResult.getDecryptionMetadata();
+ String fileName = metadata.getFilename();
+ String contentType = metadata.getMimeType();
+ if (!TextUtils.isEmpty(fileName)
+ || contentType != null
+ && !contentType.startsWith("multipart/")
+ && !contentType.startsWith("text/")
+ && !"application/octet-stream".equals(contentType)) {
skipMimeParsing = true;
}
}
@@ -153,6 +164,7 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> {
parser.setContentDecoding(true);
parser.setRecurse();
parser.setContentHandler(new AbstractContentHandler() {
+ private boolean mFoundHeaderWithFields = false;
private Uri uncheckedSignedDataUri;
String mFilename;
@@ -185,7 +197,7 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> {
log.add(LogType.MSG_DATA_DETACHED_RAW, 3);
- uncheckedSignedDataUri = TemporaryStorageProvider.createFile(mContext, mFilename, "text/plain");
+ uncheckedSignedDataUri = TemporaryFileProvider.createFile(mContext, mFilename, "text/plain");
OutputStream out = mContext.getContentResolver().openOutputStream(uncheckedSignedDataUri, "w");
if (out == null) {
@@ -209,11 +221,19 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> {
}
@Override
+ public void endHeader() throws MimeException {
+ if ( ! mFoundHeaderWithFields) {
+ parser.stop();
+ }
+ }
+
+ @Override
public void field(Field field) throws MimeException {
field = DefaultFieldParser.getParser().parse(field, DecodeMonitor.SILENT);
if (field instanceof ContentDispositionField) {
mFilename = ((ContentDispositionField) field).getFilename();
}
+ mFoundHeaderWithFields = true;
}
private void bodySignature(BodyDescriptor bd, InputStream is) throws MimeException, IOException {
@@ -282,12 +302,24 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> {
log.add(LogType.MSG_DATA_MIME_PART, 2);
- log.add(LogType.MSG_DATA_MIME_TYPE, 3, bd.getMimeType());
+ String mimeType = bd.getMimeType();
+
if (mFilename != null) {
log.add(LogType.MSG_DATA_MIME_FILENAME, 3, mFilename);
+ boolean isGenericMimeType = ClipDescription.compareMimeTypes(mimeType, "application/octet-stream")
+ || ClipDescription.compareMimeTypes(mimeType, "application/x-download");
+ if (isGenericMimeType) {
+ String extension = MimeTypeMap.getFileExtensionFromUrl(mFilename);
+ String extMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+ if (extMimeType != null) {
+ mimeType = extMimeType;
+ log.add(LogType.MSG_DATA_MIME_FROM_EXTENSION, 3);
+ }
+ }
}
+ log.add(LogType.MSG_DATA_MIME_TYPE, 3, mimeType);
- Uri uri = TemporaryStorageProvider.createFile(mContext, mFilename, bd.getMimeType());
+ Uri uri = TemporaryFileProvider.createFile(mContext, mFilename, mimeType);
OutputStream out = mContext.getContentResolver().openOutputStream(uri, "w");
if (out == null) {
@@ -308,7 +340,7 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> {
charset = "utf-8";
}
- OpenPgpMetadata metadata = new OpenPgpMetadata(mFilename, bd.getMimeType(), 0L, totalLength, charset);
+ OpenPgpMetadata metadata = new OpenPgpMetadata(mFilename, mimeType, 0L, totalLength, charset);
out.close();
outputUris.add(uri);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java
index 8f1abde83..f3ceac681 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java
@@ -20,39 +20,43 @@
package org.sufficientlysecure.keychain.operations;
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.net.Proxy;
-import java.util.ArrayList;
-import java.util.List;
-
import android.content.Context;
import android.support.annotation.NonNull;
+import com.textuality.keybase.lib.KeybaseQuery;
import com.textuality.keybase.lib.Proof;
import com.textuality.keybase.lib.prover.Prover;
-import de.measite.minidns.Client;
-import de.measite.minidns.DNSMessage;
-import de.measite.minidns.Question;
-import de.measite.minidns.Record;
-import de.measite.minidns.record.Data;
-import de.measite.minidns.record.TXT;
+
import org.json.JSONObject;
import org.spongycastle.openpgp.PGPUtil;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.operations.results.KeybaseVerificationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
-import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeybaseVerificationParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
+import org.sufficientlysecure.keychain.util.OkHttpKeybaseClient;
import org.sufficientlysecure.keychain.util.Preferences;
import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.Proxy;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.measite.minidns.Client;
+import de.measite.minidns.DNSMessage;
+import de.measite.minidns.Question;
+import de.measite.minidns.Record;
+import de.measite.minidns.record.Data;
+import de.measite.minidns.record.TXT;
+
public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificationParcel> {
public KeybaseVerificationOperation(Context context, ProviderHelper providerHelper,
@@ -83,6 +87,9 @@ public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificat
log.add(OperationResult.LogType.MSG_KEYBASE_VERIFICATION, 0, requiredFingerprint);
try {
+ KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient());
+ keybaseQuery.setProxy(proxy);
+
String keybaseProof = keybaseInput.mKeybaseProof;
Proof proof = new Proof(new JSONObject(keybaseProof));
mProgressable.setProgress(R.string.keybase_message_fetching_data, 0, 100);
@@ -95,7 +102,7 @@ public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificat
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
- if (!prover.fetchProofData(proxy)) {
+ if (!prover.fetchProofData(keybaseQuery)) {
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_FETCH_PROOF, 1);
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
@@ -144,7 +151,6 @@ public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificat
PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(mContext, mProviderHelper, mProgressable);
PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(messageBytes)
- .setSignedLiteralData(true)
.setRequiredSignerFingerprint(requiredFingerprint);
DecryptVerifyResult decryptVerifyResult = op.execute(input, new CryptoInputParcel());
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java
index 975cf541a..3e787560a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java
@@ -19,12 +19,13 @@
package org.sufficientlysecure.keychain.operations;
+
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
+import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.RevokeResult;
import org.sufficientlysecure.keychain.pgp.Progressable;
@@ -79,9 +80,8 @@ public class RevokeOperation extends BaseOperation<RevokeKeyringParcel> {
saveKeyringParcel.mRevokeSubKeys.add(masterKeyId);
- InputPendingResult revokeAndUploadResult = new EditKeyOperation(mContext,
- mProviderHelper, mProgressable, mCancelled)
- .execute(saveKeyringParcel, cryptoInputParcel);
+ EditKeyResult revokeAndUploadResult = new EditKeyOperation(mContext,
+ mProviderHelper, mProgressable, mCancelled).execute(saveKeyringParcel, cryptoInputParcel);
if (revokeAndUploadResult.isPending()) {
return revokeAndUploadResult;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java
index 843a55389..2ca74063c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java
@@ -17,6 +17,16 @@
package org.sufficientlysecure.keychain.operations;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
@@ -40,21 +50,13 @@ import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressScaler;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicBoolean;
-/** This is a high-level operation, which encapsulates one or more sign/encrypt
+/**
+ * This is a high-level operation, which encapsulates one or more sign/encrypt
* operations, using URIs or byte arrays as input and output.
*
* This operation is fail-fast: If any sign/encrypt sub-operation fails or returns
* a pending result, it will terminate.
- *
*/
public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> {
@@ -63,6 +65,7 @@ public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> {
super(context, providerHelper, progressable, cancelled);
}
+
@NonNull
public SignEncryptResult execute(SignEncryptParcel input, CryptoInputParcel cryptoInput) {
@@ -115,7 +118,7 @@ public class SignEncryptOperation extends BaseOperation<SignEncryptParcel> {
log.add(LogType.MSG_SE_INPUT_URI, 1);
Uri uri = inputUris.removeFirst();
try {
- InputStream is = mContext.getContentResolver().openInputStream(uri);
+ InputStream is = FileHelper.openInputStreamSafe(mContext.getContentResolver(), uri);
long fileSize = FileHelper.getFileSize(mContext, uri, 0);
String filename = FileHelper.getFilename(mContext, uri);
inputData = new InputData(is, fileSize, filename);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/UploadOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/UploadOperation.java
new file mode 100644
index 000000000..e5f11eaa6
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/UploadOperation.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
+ * Copyright (C) 2015 Vincent Breitmoser <valodim@mugenguild.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.operations;
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.Proxy;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.spongycastle.bcpg.ArmoredOutputStream;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
+import org.sufficientlysecure.keychain.keyimport.Keyserver.AddKeyException;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
+import org.sufficientlysecure.keychain.operations.results.UploadResult;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
+import org.sufficientlysecure.keychain.pgp.Progressable;
+import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.UploadKeyringParcel;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
+import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
+import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.ParcelableProxy;
+import org.sufficientlysecure.keychain.util.Preferences;
+import org.sufficientlysecure.keychain.util.Preferences.ProxyPrefs;
+import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
+
+
+/**
+ * An operation class which implements the upload of a single key to a key server.
+ */
+public class UploadOperation extends BaseOperation<UploadKeyringParcel> {
+
+ public UploadOperation(Context context, ProviderHelper providerHelper,
+ Progressable progressable, AtomicBoolean cancelled) {
+ super(context, providerHelper, progressable, cancelled);
+ }
+
+ @NonNull
+ public UploadResult execute(UploadKeyringParcel uploadInput, CryptoInputParcel cryptoInput) {
+ OperationLog log = new OperationLog();
+
+ log.add(LogType.MSG_UPLOAD, 0);
+ updateProgress(R.string.progress_uploading, 0, 1);
+
+ Proxy proxy;
+ {
+ boolean proxyIsTor = false;
+
+ // Proxy priorities:
+ // 1. explicit proxy
+ // 2. orbot proxy state
+ // 3. proxy from preferences
+ ParcelableProxy parcelableProxy = cryptoInput.getParcelableProxy();
+ if (parcelableProxy != null) {
+ proxy = parcelableProxy.getProxy();
+ } else {
+ if ( ! OrbotHelper.isOrbotInRequiredState(mContext)) {
+ return new UploadResult(log, RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput);
+ }
+ ProxyPrefs proxyPrefs = Preferences.getPreferences(mContext).getProxyPrefs();
+ if (proxyPrefs.torEnabled) {
+ proxyIsTor = true;
+ }
+ proxy = proxyPrefs.getProxy();
+ }
+
+ if (proxyIsTor) {
+ log.add(LogType.MSG_UPLOAD_PROXY_TOR, 1);
+ } else if (proxy == Proxy.NO_PROXY) {
+ log.add(LogType.MSG_UPLOAD_PROXY_DIRECT, 1);
+ } else {
+ log.add(LogType.MSG_UPLOAD_PROXY, 1, proxy.toString());
+ }
+
+ }
+
+ HkpKeyserver hkpKeyserver;
+ {
+ hkpKeyserver = new HkpKeyserver(uploadInput.mKeyserver, proxy);
+ log.add(LogType.MSG_UPLOAD_SERVER, 1, hkpKeyserver.toString());
+ }
+
+ CanonicalizedPublicKeyRing keyring = getPublicKeyringFromInput(log, uploadInput);
+ if (keyring == null) {
+ return new UploadResult(UploadResult.RESULT_ERROR, log);
+ }
+
+ return uploadKeyRingToServer(log, hkpKeyserver, keyring);
+ }
+
+ @Nullable
+ private CanonicalizedPublicKeyRing getPublicKeyringFromInput(OperationLog log, UploadKeyringParcel uploadInput) {
+
+ boolean hasMasterKeyId = uploadInput.mMasterKeyId != null;
+ boolean hasKeyringBytes = uploadInput.mUncachedKeyringBytes != null;
+ if (hasMasterKeyId == hasKeyringBytes) {
+ throw new IllegalArgumentException("either keyid xor bytes must be non-null for this method call!");
+ }
+
+ try {
+
+ if (hasMasterKeyId) {
+ log.add(LogType.MSG_UPLOAD_KEY, 0, KeyFormattingUtils.convertKeyIdToHex(uploadInput.mMasterKeyId));
+ return mProviderHelper.getCanonicalizedPublicKeyRing(uploadInput.mMasterKeyId);
+ }
+
+ CanonicalizedKeyRing canonicalizedRing =
+ UncachedKeyRing.decodeFromData(uploadInput.mUncachedKeyringBytes)
+ .canonicalize(new OperationLog(), 0, true);
+ if ( ! CanonicalizedPublicKeyRing.class.isInstance(canonicalizedRing)) {
+ throw new IllegalArgumentException("keyring bytes must contain public key ring!");
+ }
+ log.add(LogType.MSG_UPLOAD_KEY, 0, KeyFormattingUtils.convertKeyIdToHex(canonicalizedRing.getMasterKeyId()));
+ return (CanonicalizedPublicKeyRing) canonicalizedRing;
+
+ } catch (ProviderHelper.NotFoundException e) {
+ log.add(LogType.MSG_UPLOAD_ERROR_NOT_FOUND, 1);
+ return null;
+ } catch (IOException | PgpGeneralException e) {
+ log.add(LogType.MSG_UPLOAD_ERROR_IO, 1);
+ Log.e(Constants.TAG, "error uploading key", e);
+ return null;
+ }
+
+ }
+
+ @NonNull
+ private UploadResult uploadKeyRingToServer(
+ OperationLog log, HkpKeyserver server, CanonicalizedPublicKeyRing keyring) {
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ArmoredOutputStream aos = null;
+
+ try {
+ aos = new ArmoredOutputStream(bos);
+ keyring.encode(aos);
+ aos.close();
+
+ String armoredKey = bos.toString("UTF-8");
+ server.add(armoredKey);
+
+ updateProgress(R.string.progress_uploading, 1, 1);
+
+ log.add(LogType.MSG_UPLOAD_SUCCESS, 1);
+ return new UploadResult(UploadResult.RESULT_OK, log);
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException", e);
+
+ log.add(LogType.MSG_UPLOAD_ERROR_IO, 1);
+ return new UploadResult(UploadResult.RESULT_ERROR, log);
+ } catch (AddKeyException e) {
+ Log.e(Constants.TAG, "AddKeyException", e);
+
+ log.add(LogType.MSG_UPLOAD_ERROR_UPLOAD, 1);
+ return new UploadResult(UploadResult.RESULT_ERROR, log);
+ } finally {
+ try {
+ if (aos != null) {
+ aos.close();
+ }
+ bos.close();
+ } catch (IOException e) {
+ // this is just a finally thing, no matter if it doesn't work out.
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/BenchmarkResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/BenchmarkResult.java
new file mode 100644
index 000000000..473ae9886
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/BenchmarkResult.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.operations.results;
+
+import android.os.Parcel;
+
+
+public class BenchmarkResult extends OperationResult {
+
+ public BenchmarkResult(int result, OperationLog log) {
+ super(result, log);
+ }
+
+ /** Construct from a parcel - trivial because we have no extra data. */
+ public BenchmarkResult(Parcel source) {
+ super(source);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ }
+
+ public static Creator<BenchmarkResult> CREATOR = new Creator<BenchmarkResult>() {
+ public BenchmarkResult createFromParcel(final Parcel source) {
+ return new BenchmarkResult(source);
+ }
+
+ public BenchmarkResult[] newArray(final int size) {
+ return new BenchmarkResult[size];
+ }
+ };
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java
index 95cf179af..f19ba5250 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java
@@ -39,6 +39,8 @@ public class DecryptVerifyResult extends InputPendingResult {
byte[] mOutputBytes;
+ public long mOperationTime;
+
public DecryptVerifyResult(int result, OperationLog log) {
super(result, log);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java
index 6098d59d5..fa383a7b5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/EditKeyResult.java
@@ -38,6 +38,11 @@ public class EditKeyResult extends InputPendingResult {
mMasterKeyId = null;
}
+ public EditKeyResult(OperationLog log, InputPendingResult result) {
+ super(log, result);
+ mMasterKeyId = null;
+ }
+
public EditKeyResult(Parcel source) {
super(source);
mMasterKeyId = source.readInt() != 0 ? source.readLong() : null;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ExportResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ExportResult.java
index e21ef949f..135f5af3d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ExportResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ExportResult.java
@@ -24,39 +24,18 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
public class ExportResult extends InputPendingResult {
- final int mOkPublic, mOkSecret;
-
public ExportResult(int result, OperationLog log) {
- this(result, log, 0, 0);
- }
-
- public ExportResult(int result, OperationLog log, int okPublic, int okSecret) {
super(result, log);
- mOkPublic = okPublic;
- mOkSecret = okSecret;
- }
-
-
- public ExportResult(OperationLog log, RequiredInputParcel requiredInputParcel,
- CryptoInputParcel cryptoInputParcel) {
- super(log, requiredInputParcel, cryptoInputParcel);
- // we won't use these values
- mOkPublic = -1;
- mOkSecret = -1;
}
/** Construct from a parcel - trivial because we have no extra data. */
public ExportResult(Parcel source) {
super(source);
- mOkPublic = source.readInt();
- mOkSecret = source.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
- dest.writeInt(mOkPublic);
- dest.writeInt(mOkSecret);
}
public static Creator<ExportResult> CREATOR = new Creator<ExportResult>() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java
index 0a8c1f653..ed6674ef7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java
@@ -19,6 +19,7 @@
package org.sufficientlysecure.keychain.operations.results;
import android.os.Parcel;
+import android.support.annotation.NonNull;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
@@ -32,13 +33,13 @@ public class InputPendingResult extends OperationResult {
// in case operation needs to add to/changes the cryptoInputParcel sent to it
public final CryptoInputParcel mCryptoInputParcel;
- public InputPendingResult(int result, OperationLog log) {
+ public InputPendingResult(int result, @NonNull OperationLog log) {
super(result, log);
mRequiredInput = null;
mCryptoInputParcel = null;
}
- public InputPendingResult(OperationLog log, InputPendingResult result) {
+ public InputPendingResult(@NonNull OperationLog log, @NonNull InputPendingResult result) {
super(RESULT_PENDING, log);
if (!result.isPending()) {
throw new AssertionError("sub result must be pending!");
@@ -47,7 +48,7 @@ public class InputPendingResult extends OperationResult {
mCryptoInputParcel = result.mCryptoInputParcel;
}
- public InputPendingResult(OperationLog log, RequiredInputParcel requiredInput,
+ public InputPendingResult(@NonNull OperationLog log, RequiredInputParcel requiredInput,
CryptoInputParcel cryptoInputParcel) {
super(RESULT_PENDING, log);
mRequiredInput = requiredInput;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
index a03658808..9877f2318 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
@@ -474,6 +474,7 @@ public abstract class OperationResult implements Parcelable {
MSG_KC_UID_BAD (LogLevel.WARN, R.string.msg_kc_uid_bad),
MSG_KC_UID_CERT_DUP (LogLevel.DEBUG, R.string.msg_kc_uid_cert_dup),
MSG_KC_UID_DUP (LogLevel.DEBUG, R.string.msg_kc_uid_dup),
+ MSG_KC_UID_TOO_MANY (LogLevel.DEBUG, R.string.msg_kc_uid_too_many),
MSG_KC_UID_FOREIGN (LogLevel.DEBUG, R.string.msg_kc_uid_foreign),
MSG_KC_UID_NO_CERT (LogLevel.DEBUG, R.string.msg_kc_uid_no_cert),
MSG_KC_UID_REVOKE_DUP (LogLevel.DEBUG, R.string.msg_kc_uid_revoke_dup),
@@ -513,7 +514,7 @@ public abstract class OperationResult implements Parcelable {
MSG_CR_ERROR_NO_USER_ID (LogLevel.ERROR, R.string.msg_cr_error_no_user_id),
MSG_CR_ERROR_NO_CERTIFY (LogLevel.ERROR, R.string.msg_cr_error_no_certify),
MSG_CR_ERROR_NULL_EXPIRY(LogLevel.ERROR, R.string.msg_cr_error_null_expiry),
- MSG_CR_ERROR_KEYSIZE_512 (LogLevel.ERROR, R.string.msg_cr_error_keysize_512),
+ MSG_CR_ERROR_KEYSIZE_2048(LogLevel.ERROR, R.string.msg_cr_error_keysize_2048),
MSG_CR_ERROR_NO_KEYSIZE (LogLevel.ERROR, R.string.msg_cr_error_no_keysize),
MSG_CR_ERROR_NO_CURVE (LogLevel.ERROR, R.string.msg_cr_error_no_curve),
MSG_CR_ERROR_UNKNOWN_ALGO (LogLevel.ERROR, R.string.msg_cr_error_unknown_algo),
@@ -634,10 +635,13 @@ public abstract class OperationResult implements Parcelable {
MSG_EK_ERROR_NOT_FOUND (LogLevel.ERROR, R.string.msg_ek_error_not_found),
// decryptverify
+ MSG_DC_ASKIP_BAD_FLAGS (LogLevel.DEBUG, R.string.msg_dc_askip_bad_flags),
+ MSG_DC_ASKIP_UNAVAILABLE (LogLevel.DEBUG, R.string.msg_dc_askip_unavailable),
MSG_DC_ASKIP_NO_KEY (LogLevel.DEBUG, R.string.msg_dc_askip_no_key),
MSG_DC_ASKIP_NOT_ALLOWED (LogLevel.DEBUG, R.string.msg_dc_askip_not_allowed),
MSG_DC_ASYM (LogLevel.DEBUG, R.string.msg_dc_asym),
MSG_DC_CHARSET (LogLevel.DEBUG, R.string.msg_dc_charset),
+ MSG_DC_BACKUP_VERSION (LogLevel.DEBUG, R.string.msg_dc_backup_version),
MSG_DC_CLEAR_DATA (LogLevel.DEBUG, R.string.msg_dc_clear_data),
MSG_DC_CLEAR_DECOMPRESS (LogLevel.DEBUG, R.string.msg_dc_clear_decompress),
MSG_DC_CLEAR_META_FILE (LogLevel.DEBUG, R.string.msg_dc_clear_meta_file),
@@ -660,6 +664,7 @@ public abstract class OperationResult implements Parcelable {
MSG_DC_ERROR_INPUT (LogLevel.ERROR, R.string.msg_dc_error_input),
MSG_DC_ERROR_NO_DATA (LogLevel.ERROR, R.string.msg_dc_error_no_data),
MSG_DC_ERROR_NO_KEY (LogLevel.ERROR, R.string.msg_dc_error_no_key),
+ MSG_DC_ERROR_NO_SIGNATURE (LogLevel.ERROR, R.string.msg_dc_error_no_signature),
MSG_DC_ERROR_PGP_EXCEPTION (LogLevel.ERROR, R.string.msg_dc_error_pgp_exception),
MSG_DC_INTEGRITY_CHECK_OK (LogLevel.INFO, R.string.msg_dc_integrity_check_ok),
MSG_DC_OK_META_ONLY (LogLevel.OK, R.string.msg_dc_ok_meta_only),
@@ -686,6 +691,7 @@ public abstract class OperationResult implements Parcelable {
MSG_VL_ERROR_MISSING_SIGLIST (LogLevel.ERROR, R.string.msg_vl_error_no_siglist),
MSG_VL_ERROR_MISSING_LITERAL (LogLevel.ERROR, R.string.msg_vl_error_missing_literal),
MSG_VL_ERROR_MISSING_KEY (LogLevel.ERROR, R.string.msg_vl_error_wrong_key),
+ MSG_VL_ERROR_NO_SIGNATURE (LogLevel.ERROR, R.string.msg_vl_error_no_signature),
MSG_VL_CLEAR_SIGNATURE_CHECK (LogLevel.DEBUG, R.string.msg_vl_clear_signature_check),
MSG_VL_ERROR_INTEGRITY_CHECK (LogLevel.ERROR, R.string.msg_vl_error_integrity_check),
MSG_VL_OK (LogLevel.OK, R.string.msg_vl_ok),
@@ -702,7 +708,6 @@ public abstract class OperationResult implements Parcelable {
// pgpsignencrypt
MSG_PSE_ASYMMETRIC (LogLevel.INFO, R.string.msg_pse_asymmetric),
- MSG_PSE_CLEARSIGN_ONLY (LogLevel.DEBUG, R.string.msg_pse_clearsign_only),
MSG_PSE_COMPRESSING (LogLevel.DEBUG, R.string.msg_pse_compressing),
MSG_PSE_ENCRYPTING (LogLevel.DEBUG, R.string.msg_pse_encrypting),
MSG_PSE_ERROR_BAD_PASSPHRASE (LogLevel.ERROR, R.string.msg_pse_error_bad_passphrase),
@@ -762,23 +767,25 @@ public abstract class OperationResult implements Parcelable {
MSG_IMPORT_PARTIAL (LogLevel.ERROR, R.string.msg_import_partial),
MSG_IMPORT_SUCCESS (LogLevel.OK, R.string.msg_import_success),
- MSG_EXPORT (LogLevel.START, R.plurals.msg_export),
- MSG_EXPORT_FILE_NAME (LogLevel.INFO, R.string.msg_export_file_name),
- MSG_EXPORT_UPLOAD_PUBLIC (LogLevel.START, R.string.msg_export_upload_public),
- MSG_EXPORT_PUBLIC (LogLevel.DEBUG, R.string.msg_export_public),
- MSG_EXPORT_SECRET (LogLevel.DEBUG, R.string.msg_export_secret),
- MSG_EXPORT_ALL (LogLevel.START, R.string.msg_export_all),
- MSG_EXPORT_ERROR_NO_FILE (LogLevel.ERROR, R.string.msg_export_error_no_file),
- MSG_EXPORT_ERROR_FOPEN (LogLevel.ERROR, R.string.msg_export_error_fopen),
- MSG_EXPORT_ERROR_NO_URI (LogLevel.ERROR, R.string.msg_export_error_no_uri),
- MSG_EXPORT_ERROR_URI_OPEN (LogLevel.ERROR, R.string.msg_export_error_uri_open),
- MSG_EXPORT_ERROR_STORAGE (LogLevel.ERROR, R.string.msg_export_error_storage),
- MSG_EXPORT_ERROR_DB (LogLevel.ERROR, R.string.msg_export_error_db),
- MSG_EXPORT_ERROR_IO (LogLevel.ERROR, R.string.msg_export_error_io),
- MSG_EXPORT_ERROR_KEY (LogLevel.ERROR, R.string.msg_export_error_key),
- MSG_EXPORT_ERROR_UPLOAD (LogLevel.ERROR, R.string.msg_export_error_upload),
- MSG_EXPORT_SUCCESS (LogLevel.OK, R.string.msg_export_success),
- MSG_EXPORT_UPLOAD_SUCCESS (LogLevel.OK, R.string.msg_export_upload_success),
+ MSG_BACKUP(LogLevel.START, R.plurals.msg_backup),
+ MSG_BACKUP_PUBLIC(LogLevel.DEBUG, R.string.msg_backup_public),
+ MSG_BACKUP_SECRET(LogLevel.DEBUG, R.string.msg_backup_secret),
+ MSG_BACKUP_ALL(LogLevel.START, R.string.msg_backup_all),
+ MSG_BACKUP_ERROR_URI_OPEN(LogLevel.ERROR, R.string.msg_backup_error_uri_open),
+ MSG_BACKUP_ERROR_DB(LogLevel.ERROR, R.string.msg_backup_error_db),
+ MSG_BACKUP_ERROR_IO(LogLevel.ERROR, R.string.msg_backup_error_io),
+ MSG_BACKUP_SUCCESS(LogLevel.OK, R.string.msg_backup_success),
+
+ MSG_UPLOAD(LogLevel.START, R.string.msg_upload),
+ MSG_UPLOAD_KEY(LogLevel.INFO, R.string.msg_upload_key),
+ MSG_UPLOAD_PROXY_DIRECT(LogLevel.DEBUG, R.string.msg_upload_proxy_direct),
+ MSG_UPLOAD_PROXY_TOR(LogLevel.DEBUG, R.string.msg_upload_proxy_tor),
+ MSG_UPLOAD_PROXY(LogLevel.DEBUG, R.string.msg_upload_proxy),
+ MSG_UPLOAD_SERVER(LogLevel.DEBUG, R.string.msg_upload_server),
+ MSG_UPLOAD_SUCCESS(LogLevel.OK, R.string.msg_upload_success),
+ MSG_UPLOAD_ERROR_NOT_FOUND(LogLevel.ERROR, R.string.msg_upload_error_not_found),
+ MSG_UPLOAD_ERROR_IO(LogLevel.ERROR, R.string.msg_upload_error_key),
+ MSG_UPLOAD_ERROR_UPLOAD(LogLevel.ERROR, R.string.msg_upload_error_upload),
MSG_CRT_UPLOAD_SUCCESS (LogLevel.OK, R.string.msg_crt_upload_success),
@@ -829,7 +836,6 @@ public abstract class OperationResult implements Parcelable {
MSG_DATA (LogLevel.START, R.string.msg_data),
MSG_DATA_OPENPGP (LogLevel.DEBUG, R.string.msg_data_openpgp),
MSG_DATA_ERROR_IO (LogLevel.ERROR, R.string.msg_data_error_io),
- MSG_DATA_ERROR_OPENPGP (LogLevel.ERROR, R.string.msg_data_error_openpgp),
MSG_DATA_DETACHED (LogLevel.INFO, R.string.msg_data_detached),
MSG_DATA_DETACHED_CLEAR (LogLevel.WARN, R.string.msg_data_detached_clear),
MSG_DATA_DETACHED_SIG (LogLevel.DEBUG, R.string.msg_data_detached_sig),
@@ -838,6 +844,7 @@ public abstract class OperationResult implements Parcelable {
MSG_DATA_DETACHED_TRAILING (LogLevel.WARN, R.string.msg_data_detached_trailing),
MSG_DATA_DETACHED_UNSUPPORTED (LogLevel.WARN, R.string.msg_data_detached_unsupported),
MSG_DATA_MIME_BAD(LogLevel.INFO, R.string.msg_data_mime_bad),
+ MSG_DATA_MIME_FROM_EXTENSION (LogLevel.DEBUG, R.string.msg_data_mime_from_extension),
MSG_DATA_MIME_FILENAME (LogLevel.DEBUG, R.string.msg_data_mime_filename),
MSG_DATA_MIME_LENGTH (LogLevel.DEBUG, R.string.msg_data_mime_length),
MSG_DATA_MIME (LogLevel.DEBUG, R.string.msg_data_mime),
@@ -868,6 +875,16 @@ public abstract class OperationResult implements Parcelable {
MSG_LV_FETCH_ERROR_IO (LogLevel.ERROR, R.string.msg_lv_fetch_error_io),
MSG_LV_FETCH_ERROR_FORMAT(LogLevel.ERROR, R.string.msg_lv_fetch_error_format),
MSG_LV_FETCH_ERROR_NOTHING (LogLevel.ERROR, R.string.msg_lv_fetch_error_nothing),
+
+ MSG_BENCH (LogLevel.START, R.string.msg_bench),
+ MSG_BENCH_ENC_TIME (LogLevel.DEBUG, R.string.msg_bench_enc_time),
+ MSG_BENCH_ENC_TIME_AVG (LogLevel.INFO, R.string.msg_bench_enc_time_avg),
+ MSG_BENCH_DEC_TIME (LogLevel.DEBUG, R.string.msg_bench_dec_time),
+ MSG_BENCH_DEC_TIME_AVG (LogLevel.INFO, R.string.msg_bench_enc_time_avg),
+ MSG_BENCH_S2K_FOR_IT (LogLevel.DEBUG, R.string.msg_bench_s2k_for_it),
+ MSG_BENCH_S2K_100MS_ITS (LogLevel.INFO, R.string.msg_bench_s2k_100ms_its),
+ MSG_BENCH_SUCCESS (LogLevel.OK, R.string.msg_bench_success),
+
;
public final int mMsgId;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java
index 2b33b8ace..12b091e32 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java
@@ -26,6 +26,7 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
public class PgpSignEncryptResult extends InputPendingResult {
byte[] mDetachedSignature;
+ public long mOperationTime;
public void setDetachedSignature(byte[] detachedSignature) {
mDetachedSignature = detachedSignature;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java
index 0e0c5d598..60f47be3c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java
@@ -56,6 +56,10 @@ public class SignEncryptResult extends InputPendingResult {
return mResultBytes;
}
+ public ArrayList<PgpSignEncryptResult> getResults() {
+ return mResults;
+ }
+
public int describeContents() {
return 0;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/UploadResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/UploadResult.java
new file mode 100644
index 000000000..ea2b373a9
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/UploadResult.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.operations.results;
+
+import android.os.Parcel;
+import android.support.annotation.NonNull;
+
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
+
+
+public class UploadResult extends InputPendingResult {
+
+ final int mOkPublic, mOkSecret;
+
+ public UploadResult(int result, OperationLog log) {
+ this(result, log, 0, 0);
+ }
+
+ public UploadResult(int result, OperationLog log, int okPublic, int okSecret) {
+ super(result, log);
+ mOkPublic = okPublic;
+ mOkSecret = okSecret;
+ }
+
+
+ public UploadResult(@NonNull OperationLog log, RequiredInputParcel requiredInputParcel,
+ CryptoInputParcel cryptoInputParcel) {
+ super(log, requiredInputParcel, cryptoInputParcel);
+ // we won't use these values
+ mOkPublic = -1;
+ mOkSecret = -1;
+ }
+
+ /** Construct from a parcel - trivial because we have no extra data. */
+ public UploadResult(Parcel source) {
+ super(source);
+ mOkPublic = source.readInt();
+ mOkSecret = source.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(mOkPublic);
+ dest.writeInt(mOkSecret);
+ }
+
+ public static Creator<UploadResult> CREATOR = new Creator<UploadResult>() {
+ public UploadResult createFromParcel(final Parcel source) {
+ return new UploadResult(source);
+ }
+
+ public UploadResult[] newArray(final int size) {
+ return new UploadResult[size];
+ }
+ };
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
index 18a27dd96..6f1e78ce6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java
@@ -154,8 +154,13 @@ public abstract class CanonicalizedKeyRing extends KeyRing {
return getRing().getEncoded();
}
- public boolean containsSubkey(String expectedFingerprint) {
+ /// Returns true iff the keyring contains a primary key or mutually bound subkey with the expected fingerprint
+ public boolean containsBoundSubkey(String expectedFingerprint) {
for (CanonicalizedPublicKey key : publicKeyIterator()) {
+ boolean isMasterOrMutuallyBound = key.isMasterKey() || key.canSign();
+ if (!isMasterOrMutuallyBound) {
+ continue;
+ }
if (KeyFormattingUtils.convertFingerprintToHex(
key.getFingerprint()).equalsIgnoreCase(expectedFingerprint)) {
return true;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java
index 412468a48..476b4e59c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java
@@ -44,13 +44,17 @@ import java.util.Iterator;
public class CanonicalizedPublicKey extends UncachedPublicKey {
// this is the parent key ring
- final KeyRing mRing;
+ final CanonicalizedKeyRing mRing;
- CanonicalizedPublicKey(KeyRing ring, PGPPublicKey key) {
+ CanonicalizedPublicKey(CanonicalizedKeyRing ring, PGPPublicKey key) {
super(key);
mRing = ring;
}
+ public CanonicalizedKeyRing getKeyRing() {
+ return mRing;
+ }
+
public IterableIterator<String> getUserIds() {
return new IterableIterator<String>(mPublicKey.getUserIDs());
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java
index 9d059b58f..2dd1e2dde 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java
@@ -91,11 +91,12 @@ public class OpenPgpSignatureResultBuilder {
return mInsecure;
}
- public void initValid(CanonicalizedPublicKeyRing signingRing,
- CanonicalizedPublicKey signingKey) {
+ public void initValid(CanonicalizedPublicKey signingKey) {
setSignatureAvailable(true);
setKnownKey(true);
+ CanonicalizedKeyRing signingRing = signingKey.getKeyRing();
+
// from RING
setKeyId(signingRing.getMasterKeyId());
try {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyInputParcel.java
index 3eef7759c..bc9b54cd6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyInputParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyInputParcel.java
@@ -18,7 +18,7 @@
package org.sufficientlysecure.keychain.pgp;
-import java.io.InputStream;
+
import java.util.HashSet;
import android.net.Uri;
@@ -36,7 +36,6 @@ public class PgpDecryptVerifyInputParcel implements Parcelable {
private boolean mDecryptMetadataOnly;
private byte[] mDetachedSignature;
private String mRequiredSignerFingerprint;
- private boolean mSignedLiteralData;
public PgpDecryptVerifyInputParcel() {
}
@@ -61,7 +60,6 @@ public class PgpDecryptVerifyInputParcel implements Parcelable {
mDecryptMetadataOnly = source.readInt() != 0;
mDetachedSignature = source.createByteArray();
mRequiredSignerFingerprint = source.readString();
- mSignedLiteralData = source.readInt() != 0;
}
@Override
@@ -80,7 +78,6 @@ public class PgpDecryptVerifyInputParcel implements Parcelable {
dest.writeInt(mDecryptMetadataOnly ? 1 : 0);
dest.writeByteArray(mDetachedSignature);
dest.writeString(mRequiredSignerFingerprint);
- dest.writeInt(mSignedLiteralData ? 1 : 0);
}
byte[] getInputBytes() {
@@ -150,15 +147,6 @@ public class PgpDecryptVerifyInputParcel implements Parcelable {
return this;
}
- boolean isSignedLiteralData() {
- return mSignedLiteralData;
- }
-
- public PgpDecryptVerifyInputParcel setSignedLiteralData(boolean signedLiteralData) {
- mSignedLiteralData = signedLiteralData;
- return this;
- }
-
public static final Creator<PgpDecryptVerifyInputParcel> CREATOR = new Creator<PgpDecryptVerifyInputParcel>() {
public PgpDecryptVerifyInputParcel createFromParcel(final Parcel source) {
return new PgpDecryptVerifyInputParcel(source);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
index 007f686e8..ea7465209 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
@@ -18,13 +18,24 @@
package org.sufficientlysecure.keychain.pgp;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.SignatureException;
+import java.util.Date;
+import java.util.Iterator;
+
import android.content.Context;
import android.support.annotation.NonNull;
+import android.text.TextUtils;
import android.webkit.MimeTypeMap;
import org.openintents.openpgp.OpenPgpDecryptionResult;
import org.openintents.openpgp.OpenPgpMetadata;
-import org.openintents.openpgp.OpenPgpSignatureResult;
import org.spongycastle.bcpg.ArmoredInputStream;
import org.spongycastle.openpgp.PGPCompressedData;
import org.spongycastle.openpgp.PGPDataValidationException;
@@ -33,18 +44,14 @@ import org.spongycastle.openpgp.PGPEncryptedDataList;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPKeyValidationException;
import org.spongycastle.openpgp.PGPLiteralData;
-import org.spongycastle.openpgp.PGPOnePassSignature;
-import org.spongycastle.openpgp.PGPOnePassSignatureList;
import org.spongycastle.openpgp.PGPPBEEncryptedData;
import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
-import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureList;
import org.spongycastle.openpgp.PGPUtil;
-import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory;
+import org.spongycastle.openpgp.jcajce.JcaSkipMarkerPGPObjectFactory;
import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
import org.spongycastle.openpgp.operator.jcajce.CachingDataDecryptorFactory;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
import org.spongycastle.util.encoders.DecoderException;
@@ -52,13 +59,13 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Constants.key;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.BaseOperation;
+import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
-import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
-import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
@@ -68,17 +75,6 @@ import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.ProgressScaler;
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.security.SignatureException;
-import java.util.Date;
-import java.util.Iterator;
-
public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInputParcel> {
public PgpDecryptVerifyOperation(Context context, ProviderHelper providerHelper, Progressable progressable) {
@@ -91,6 +87,8 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
InputData inputData;
OutputStream outputStream;
+ long startTime = System.currentTimeMillis();
+
if (input.getInputBytes() != null) {
byte[] inputBytes = input.getInputBytes();
inputData = new InputData(new ByteArrayInputStream(inputBytes), inputBytes.length);
@@ -126,6 +124,8 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
result.setOutputBytes(outputData);
}
+ result.mOperationTime = System.currentTimeMillis() - startTime;
+ Log.d(Constants.TAG, "total time taken: " + String.format("%.2f", result.mOperationTime / 1000.0) + "s");
return result;
}
@@ -153,9 +153,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
// it is ascii armored
Log.d(Constants.TAG, "ASCII Armor Header Line: " + aIn.getArmorHeaderLine());
- if (input.isSignedLiteralData()) {
- return verifySignedLiteralData(input, aIn, outputStream, 0);
- } else if (aIn.isClearText()) {
+ if (aIn.isClearText()) {
// a cleartext signature, verify it with the other method
return verifyCleartextSignature(aIn, outputStream, 0);
} else {
@@ -186,133 +184,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
}
}
- /**Verify signed plaintext data (PGP/INLINE). */
- @NonNull
- private DecryptVerifyResult verifySignedLiteralData(
- PgpDecryptVerifyInputParcel input, InputStream in, OutputStream out, int indent)
- throws IOException, PGPException {
- OperationLog log = new OperationLog();
- log.add(LogType.MSG_VL, indent);
-
- // thinking that the proof-fetching operation is going to take most of the time
- updateProgress(R.string.progress_reading_data, 75, 100);
-
- JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in);
- Object o = pgpF.nextObject();
- if (o instanceof PGPCompressedData) {
- log.add(LogType.MSG_DC_CLEAR_DECOMPRESS, indent + 1);
-
- pgpF = new JcaPGPObjectFactory(((PGPCompressedData) o).getDataStream());
- o = pgpF.nextObject();
- updateProgress(R.string.progress_decompressing_data, 80, 100);
- }
-
- // all we want to see is a OnePassSignatureList followed by LiteralData
- if (!(o instanceof PGPOnePassSignatureList)) {
- log.add(LogType.MSG_VL_ERROR_MISSING_SIGLIST, indent);
- return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
- }
- PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) o;
-
- // go through all signatures (should be just one), make sure we have
- // the key and it matches the one we’re looking for
- CanonicalizedPublicKeyRing signingRing = null;
- CanonicalizedPublicKey signingKey = null;
- int signatureIndex = -1;
- for (int i = 0; i < sigList.size(); ++i) {
- try {
- long sigKeyId = sigList.get(i).getKeyID();
- signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
- KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
- );
- signingKey = signingRing.getPublicKey(sigKeyId);
- signatureIndex = i;
- } catch (ProviderHelper.NotFoundException e) {
- Log.d(Constants.TAG, "key not found, trying next signature...");
- }
- }
-
- // there has to be a key, and it has to be the right one
- if (signingKey == null) {
- log.add(LogType.MSG_VL_ERROR_MISSING_KEY, indent);
- Log.d(Constants.TAG, "Failed to find key in signed-literal message");
- return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
- }
-
- String fingerprint = KeyFormattingUtils.convertFingerprintToHex(signingRing.getFingerprint());
- if (!(input.getRequiredSignerFingerprint().equals(fingerprint))) {
- log.add(LogType.MSG_VL_ERROR_MISSING_KEY, indent);
- Log.d(Constants.TAG, "Fingerprint mismatch; wanted " + input.getRequiredSignerFingerprint() +
- " got " + fingerprint + "!");
- return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
- }
-
- OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
-
- PGPOnePassSignature signature = sigList.get(signatureIndex);
- signatureResultBuilder.initValid(signingRing, signingKey);
-
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
- new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey());
-
- o = pgpF.nextObject();
-
- if (!(o instanceof PGPLiteralData)) {
- log.add(LogType.MSG_VL_ERROR_MISSING_LITERAL, indent);
- return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
- }
-
- PGPLiteralData literalData = (PGPLiteralData) o;
-
- log.add(LogType.MSG_DC_CLEAR_DATA, indent + 1);
- updateProgress(R.string.progress_decrypting, 85, 100);
-
- InputStream dataIn = literalData.getInputStream();
-
- int length;
- byte[] buffer = new byte[1 << 16];
- while ((length = dataIn.read(buffer)) > 0) {
- out.write(buffer, 0, length);
- signature.update(buffer, 0, length);
- }
-
- updateProgress(R.string.progress_verifying_signature, 95, 100);
- log.add(LogType.MSG_VL_CLEAR_SIGNATURE_CHECK, indent + 1);
-
- PGPSignatureList signatureList = (PGPSignatureList) pgpF.nextObject();
- PGPSignature messageSignature = signatureList.get(signatureIndex);
-
- // Verify signature and check binding signatures
- boolean validSignature = signature.verify(messageSignature);
- if (validSignature) {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1);
- } else {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1);
- }
- signatureResultBuilder.setValidSignature(validSignature);
-
- OpenPgpSignatureResult signatureResult = signatureResultBuilder.build();
-
- if (signatureResult.getResult() != OpenPgpSignatureResult.RESULT_VALID_CONFIRMED
- && signatureResult.getResult() != OpenPgpSignatureResult.RESULT_VALID_UNCONFIRMED) {
- log.add(LogType.MSG_VL_ERROR_INTEGRITY_CHECK, indent);
- return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
- }
-
- updateProgress(R.string.progress_done, 100, 100);
-
- log.add(LogType.MSG_VL_OK, indent);
-
- // Return a positive result, with metadata and verification info
- DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log);
- result.setSignatureResult(signatureResult);
- result.setDecryptionResult(
- new OpenPgpDecryptionResult(OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED));
- return result;
- }
-
private static class EncryptStreamResult {
// this is non-null iff an error occured, return directly
@@ -335,6 +206,57 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
}
+ private static class ArmorHeaders {
+ String charset = null;
+ Integer backupVersion = null;
+ }
+
+ private ArmorHeaders parseArmorHeaders(InputStream in, OperationLog log, int indent) {
+ ArmorHeaders armorHeaders = new ArmorHeaders();
+
+ // If the input stream is armored, and there is a charset specified, take a note for later
+ // https://tools.ietf.org/html/rfc4880#page56
+ if (in instanceof ArmoredInputStream) {
+ ArmoredInputStream aIn = (ArmoredInputStream) in;
+ if (aIn.getArmorHeaders() != null) {
+ for (String header : aIn.getArmorHeaders()) {
+ String[] pieces = header.split(":", 2);
+ if (pieces.length != 2
+ || TextUtils.isEmpty(pieces[0])
+ || TextUtils.isEmpty(pieces[1])) {
+ continue;
+ }
+
+ switch (pieces[0].toLowerCase()) {
+ case "charset": {
+ armorHeaders.charset = pieces[1].trim();
+ break;
+ }
+ case "backupversion": {
+ try {
+ armorHeaders.backupVersion = Integer.valueOf(pieces[1].trim());
+ } catch (NumberFormatException e) {
+ continue;
+ }
+ break;
+ }
+ default: {
+ // continue;
+ }
+ }
+ }
+ if (armorHeaders.charset != null) {
+ log.add(LogType.MSG_DC_CHARSET, indent, armorHeaders.charset);
+ }
+ if (armorHeaders.backupVersion != null) {
+ log.add(LogType.MSG_DC_BACKUP_VERSION, indent, Integer.toString(armorHeaders.backupVersion));
+ }
+ }
+ }
+
+ return armorHeaders;
+ }
+
/** Decrypt and/or verify binary or ascii armored pgp data. */
@NonNull
private DecryptVerifyResult decryptVerify(
@@ -349,38 +271,27 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
int currentProgress = 0;
updateProgress(R.string.progress_reading_data, currentProgress, 100);
- // If the input stream is armored, and there is a charset specified, take a note for later
- // https://tools.ietf.org/html/rfc4880#page56
- String charset = null;
- if (in instanceof ArmoredInputStream) {
- ArmoredInputStream aIn = (ArmoredInputStream) in;
- if (aIn.getArmorHeaders() != null) {
- for (String header : aIn.getArmorHeaders()) {
- String[] pieces = header.split(":", 2);
- if (pieces.length == 2 && "charset".equalsIgnoreCase(pieces[0])) {
- charset = pieces[1].trim();
- break;
- }
- }
- if (charset != null) {
- log.add(LogType.MSG_DC_CHARSET, indent, charset);
- }
- }
+ // parse ASCII Armor headers
+ ArmorHeaders armorHeaders = parseArmorHeaders(in, log, indent);
+ String charset = armorHeaders.charset;
+ boolean useBackupCode = false;
+ if (armorHeaders.backupVersion != null && armorHeaders.backupVersion == 1) {
+ useBackupCode = true;
}
- OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
OpenPgpDecryptionResultBuilder decryptionResultBuilder = new OpenPgpDecryptionResultBuilder();
- JcaPGPObjectFactory plainFact;
+ JcaSkipMarkerPGPObjectFactory plainFact;
Object dataChunk;
EncryptStreamResult esResult = null;
{ // resolve encrypted (symmetric and asymmetric) packets
- JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in);
+ JcaSkipMarkerPGPObjectFactory pgpF = new JcaSkipMarkerPGPObjectFactory(in);
Object obj = pgpF.nextObject();
if (obj instanceof PGPEncryptedDataList) {
esResult = handleEncryptedPacket(
- input, cryptoInput, (PGPEncryptedDataList) obj, log, indent, currentProgress);
+ input, cryptoInput, (PGPEncryptedDataList) obj, log, indent,
+ currentProgress, useBackupCode);
// if there is an error, nothing left to do here
if (esResult.errorResult != null) {
@@ -401,7 +312,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
decryptionResultBuilder.setInsecure(true);
}
- plainFact = new JcaPGPObjectFactory(esResult.cleartextStream);
+ plainFact = new JcaSkipMarkerPGPObjectFactory(esResult.cleartextStream);
dataChunk = plainFact.nextObject();
} else {
@@ -415,10 +326,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
log.add(LogType.MSG_DC_PREP_STREAMS, indent);
- int signatureIndex = -1;
- CanonicalizedPublicKeyRing signingRing = null;
- CanonicalizedPublicKey signingKey = null;
-
log.add(LogType.MSG_DC_CLEAR, indent);
indent += 1;
@@ -430,63 +337,13 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
PGPCompressedData compressedData = (PGPCompressedData) dataChunk;
- JcaPGPObjectFactory fact = new JcaPGPObjectFactory(compressedData.getDataStream());
+ JcaSkipMarkerPGPObjectFactory fact = new JcaSkipMarkerPGPObjectFactory(compressedData.getDataStream());
dataChunk = fact.nextObject();
plainFact = fact;
}
- // resolve leading signature data
- PGPOnePassSignature signature = null;
- if (dataChunk instanceof PGPOnePassSignatureList) {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE, indent + 1);
- currentProgress += 2;
- updateProgress(R.string.progress_processing_signature, currentProgress, 100);
-
- PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
-
- // NOTE: following code is similar to processSignature, but for PGPOnePassSignature
-
- // go through all signatures
- // and find out for which signature we have a key in our database
- for (int i = 0; i < sigList.size(); ++i) {
- try {
- long sigKeyId = sigList.get(i).getKeyID();
- signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
- KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
- );
- signingKey = signingRing.getPublicKey(sigKeyId);
- signatureIndex = i;
- } catch (ProviderHelper.NotFoundException e) {
- Log.d(Constants.TAG, "key not found, trying next signature...");
- }
- }
-
- if (signingKey != null) {
- // key found in our database!
- signature = sigList.get(signatureIndex);
-
- signatureResultBuilder.initValid(signingRing, signingKey);
-
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
- new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey());
- } else {
- // no key in our database -> return "unknown pub key" status including the first key id
- if (!sigList.isEmpty()) {
- signatureResultBuilder.setSignatureAvailable(true);
- signatureResultBuilder.setKnownKey(false);
- signatureResultBuilder.setKeyId(sigList.get(0).getKeyID());
- }
- }
-
- // check for insecure signing key
- // TODO: checks on signingRing ?
- if (signingKey != null && ! PgpSecurityConstants.isSecureKey(signingKey)) {
- log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1);
- signatureResultBuilder.setInsecure(true);
- }
-
+ PgpSignatureChecker signatureChecker = new PgpSignatureChecker(mProviderHelper);
+ if (signatureChecker.initializeOnePassSignature(dataChunk, log, indent +1)) {
dataChunk = plainFact.nextObject();
}
@@ -512,8 +369,9 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
PGPLiteralData literalData = (PGPLiteralData) dataChunk;
String originalFilename = literalData.getFileName();
+ // reject filenames with slashes completely (path traversal issue)
if (originalFilename.contains("/")) {
- originalFilename = originalFilename.substring(originalFilename.lastIndexOf('/'));
+ originalFilename = "";
}
String mimeType = null;
if (literalData.getFormat() == PGPLiteralData.TEXT
@@ -534,14 +392,14 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
if (!"".equals(originalFilename)) {
log.add(LogType.MSG_DC_CLEAR_META_FILE, indent + 1, originalFilename);
}
- log.add(LogType.MSG_DC_CLEAR_META_MIME, indent + 1,
- mimeType);
log.add(LogType.MSG_DC_CLEAR_META_TIME, indent + 1,
new Date(literalData.getModificationTime().getTime()).toString());
// return here if we want to decrypt the metadata only
if (input.isDecryptMetadataOnly()) {
+ log.add(LogType.MSG_DC_CLEAR_META_MIME, indent + 1, mimeType);
+
// this operation skips the entire stream to find the data length!
Long originalSize = literalData.findDataLength();
@@ -566,23 +424,18 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
return result;
}
- int endProgress;
- if (signature != null) {
- endProgress = 90;
- } else if (esResult != null && esResult.encryptedData.isIntegrityProtected()) {
- endProgress = 95;
- } else {
- endProgress = 100;
- }
ProgressScaler progressScaler =
- new ProgressScaler(mProgressable, currentProgress, endProgress, 100);
+ new ProgressScaler(mProgressable, currentProgress, 95, 100);
InputStream dataIn = literalData.getInputStream();
+ long opTime, startTime = System.currentTimeMillis();
+
long alreadyWritten = 0;
long wholeSize = 0; // TODO inputData.getSize() - inputData.getStreamPosition();
int length;
- byte[] buffer = new byte[1 << 16];
+ byte[] buffer = new byte[8192];
+ byte[] firstBytes = new byte[48];
while ((length = dataIn.read(buffer)) > 0) {
// Log.d(Constants.TAG, "read bytes: " + length);
if (out != null) {
@@ -590,11 +443,15 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
}
// update signature buffer if signature is also present
- if (signature != null) {
- signature.update(buffer, 0, length);
+ signatureChecker.updateSignatureData(buffer, 0, length);
+
+ // note down first couple of bytes for "magic bytes" file type detection
+ if (alreadyWritten == 0) {
+ System.arraycopy(buffer, 0, firstBytes, 0, length > firstBytes.length ? firstBytes.length : length);
}
alreadyWritten += length;
+ // noinspection ConstantConditions, TODO progress
if (wholeSize > 0) {
long progress = 100 * alreadyWritten / wholeSize;
// stop at 100% for wrong file sizes...
@@ -603,36 +460,36 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
}
progressScaler.setProgress((int) progress, 100);
}
- // TODO: slow annealing to fake a progress?
}
- metadata = new OpenPgpMetadata(
- originalFilename, mimeType, literalData.getModificationTime().getTime(), alreadyWritten, charset);
+ if (signatureChecker.isInitialized()) {
- if (signature != null) {
- updateProgress(R.string.progress_verifying_signature, 90, 100);
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent);
+ Object o = plainFact.nextObject();
+ boolean signatureCheckOk = signatureChecker.verifySignatureOnePass(o, log, indent + 1);
- PGPSignatureList signatureList = (PGPSignatureList) plainFact.nextObject();
- PGPSignature messageSignature = signatureList.get(signatureIndex);
-
- // Verify signature
- boolean validSignature = signature.verify(messageSignature);
- if (validSignature) {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1);
- } else {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1);
+ if (!signatureCheckOk) {
+ return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
}
- // check for insecure hash algorithms
- if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) {
- log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1);
- signatureResultBuilder.setInsecure(true);
- }
+ }
+
+ opTime = System.currentTimeMillis()-startTime;
+ Log.d(Constants.TAG, "decrypt time taken: " + String.format("%.2f", opTime / 1000.0) + "s");
- signatureResultBuilder.setValidSignature(validSignature);
+ // special treatment to detect pgp mime types
+ if (matchesPrefix(firstBytes, "-----BEGIN PGP PUBLIC KEY BLOCK-----")
+ || matchesPrefix(firstBytes, "-----BEGIN PGP PRIVATE KEY BLOCK-----")) {
+ mimeType = Constants.MIME_TYPE_KEYS;
+ } else if (matchesPrefix(firstBytes, "-----BEGIN PGP MESSAGE-----")) {
+ // this is NOT application/pgp-encrypted, see RFC 3156!
+ mimeType = Constants.MIME_TYPE_ENCRYPTED_ALTERNATE;
}
+ log.add(LogType.MSG_DC_CLEAR_META_MIME, indent + 1, mimeType);
+
+ metadata = new OpenPgpMetadata(
+ originalFilename, mimeType, literalData.getModificationTime().getTime(), alreadyWritten, charset);
+
indent -= 1;
if (esResult != null) {
@@ -645,7 +502,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
log.add(LogType.MSG_DC_ERROR_INTEGRITY_CHECK, indent);
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
}
- } else if (signature == null) {
+ } else if ( ! signatureChecker.isInitialized() ) {
// If no signature is present, we *require* an MDC!
// Handle missing integrity protection like failed integrity protection!
// The MDC packet can be stripped by an attacker!
@@ -662,23 +519,17 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log);
result.setCachedCryptoInputParcel(cryptoInput);
- result.setSignatureResult(signatureResultBuilder.build());
+ result.setSignatureResult(signatureChecker.getSignatureResult());
result.setDecryptionResult(decryptionResultBuilder.build());
result.setDecryptionMetadata(metadata);
+ result.mOperationTime = opTime;
return result;
}
private EncryptStreamResult handleEncryptedPacket(PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput,
- PGPEncryptedDataList enc, OperationLog log, int indent, int currentProgress) throws PGPException {
-
- // TODO is this necessary?
- /*
- else if (obj instanceof PGPEncryptedDataList) {
- enc = (PGPEncryptedDataList) pgpF.nextObject();
- }
- */
+ PGPEncryptedDataList enc, OperationLog log, int indent, int currentProgress, boolean useBackupCode) throws PGPException {
EncryptStreamResult result = new EncryptStreamResult();
@@ -720,11 +571,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1);
continue;
}
- if (secretKeyRing == null) {
- // continue with the next packet in the while loop
- log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1);
- continue;
- }
// allow only specific keys for decryption?
if (input.getAllowedKeyIds() != null) {
@@ -744,9 +590,16 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
// get subkey which has been used for this encryption packet
secretEncryptionKey = secretKeyRing.getSecretKey(subKeyId);
- if (secretEncryptionKey == null) {
- // should actually never happen, so no need to be more specific.
- log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1);
+
+ if (!secretEncryptionKey.canEncrypt()) {
+ secretEncryptionKey = null;
+ log.add(LogType.MSG_DC_ASKIP_BAD_FLAGS, indent + 1);
+ continue;
+ }
+
+ if (!secretEncryptionKey.getSecretKeyType().isUsable()) {
+ secretEncryptionKey = null;
+ log.add(LogType.MSG_DC_ASKIP_UNAVAILABLE, indent + 1);
continue;
}
@@ -820,8 +673,11 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
if (passphrase == null) {
log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1);
+ RequiredInputParcel requiredInputParcel = useBackupCode ?
+ RequiredInputParcel.createRequiredBackupCode() :
+ RequiredInputParcel.createRequiredSymmetricPassphrase();
return result.with(new DecryptVerifyResult(log,
- RequiredInputParcel.createRequiredSymmetricPassphrase(),
+ requiredInputParcel,
cryptoInput));
}
@@ -864,8 +720,10 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
result.cleartextStream = encryptedDataSymmetric.getDataStream(decryptorFactory);
} catch (PGPDataValidationException e) {
log.add(LogType.MSG_DC_ERROR_SYM_PASSPHRASE, indent + 1);
- return result.with(new DecryptVerifyResult(log,
- RequiredInputParcel.createRequiredSymmetricPassphrase(), cryptoInput));
+ RequiredInputParcel requiredInputParcel = useBackupCode ?
+ RequiredInputParcel.createRequiredBackupCode() :
+ RequiredInputParcel.createRequiredSymmetricPassphrase();
+ return result.with(new DecryptVerifyResult(log, requiredInputParcel, cryptoInput));
}
result.encryptedData = encryptedDataSymmetric;
@@ -950,83 +808,53 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
OperationLog log = new OperationLog();
- OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
-
- ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] clearText;
+ { // read cleartext
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
- updateProgress(R.string.progress_reading_data, 0, 100);
+ updateProgress(R.string.progress_reading_data, 0, 100);
- ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
- int lookAhead = readInputLine(lineOut, aIn);
- byte[] lineSep = getLineSeparator();
+ ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
+ int lookAhead = readInputLine(lineOut, aIn);
+ byte[] lineSep = getLineSeparator();
- byte[] line = lineOut.toByteArray();
- out.write(line, 0, getLengthWithoutSeparator(line));
- out.write(lineSep);
-
- while (lookAhead != -1 && aIn.isClearText()) {
- lookAhead = readInputLine(lineOut, lookAhead, aIn);
- line = lineOut.toByteArray();
+ byte[] line = lineOut.toByteArray();
out.write(line, 0, getLengthWithoutSeparator(line));
out.write(lineSep);
- }
- out.close();
+ while (lookAhead != -1 && aIn.isClearText()) {
+ lookAhead = readInputLine(lineOut, lookAhead, aIn);
+ line = lineOut.toByteArray();
+ out.write(line, 0, getLengthWithoutSeparator(line));
+ out.write(lineSep);
+ }
+
+ out.close();
+ clearText = out.toByteArray();
+ }
- byte[] clearText = out.toByteArray();
if (outputStream != null) {
outputStream.write(clearText);
outputStream.close();
}
updateProgress(R.string.progress_processing_signature, 60, 100);
- JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(aIn);
+ JcaSkipMarkerPGPObjectFactory pgpFact = new JcaSkipMarkerPGPObjectFactory(aIn);
+
+ PgpSignatureChecker signatureChecker = new PgpSignatureChecker(mProviderHelper);
- PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject();
- if (sigList == null) {
+ Object o = pgpFact.nextObject();
+ if (!signatureChecker.initializeSignature(o, log, indent+1)) {
log.add(LogType.MSG_DC_ERROR_INVALID_DATA, 0);
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
}
- PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder, log, indent);
-
- if (signature != null) {
+ if (signatureChecker.isInitialized()) {
try {
updateProgress(R.string.progress_verifying_signature, 90, 100);
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent);
-
- InputStream sigIn = new BufferedInputStream(new ByteArrayInputStream(clearText));
-
- lookAhead = readInputLine(lineOut, sigIn);
-
- processLine(signature, lineOut.toByteArray());
- if (lookAhead != -1) {
- do {
- lookAhead = readInputLine(lineOut, lookAhead, sigIn);
-
- signature.update((byte) '\r');
- signature.update((byte) '\n');
-
- processLine(signature, lineOut.toByteArray());
- } while (lookAhead != -1);
- }
-
- // Verify signature and check binding signatures
- boolean validSignature = signature.verify();
- if (validSignature) {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1);
- } else {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1);
- }
-
- // check for insecure hash algorithms
- if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) {
- log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1);
- signatureResultBuilder.setInsecure(true);
- }
-
- signatureResultBuilder.setValidSignature(validSignature);
+ signatureChecker.updateSignatureWithCleartext(clearText);
+ signatureChecker.verifySignature(log, indent);
} catch (SignatureException e) {
Log.d(Constants.TAG, "SignatureException", e);
@@ -1045,7 +873,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
clearText.length);
DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log);
- result.setSignatureResult(signatureResultBuilder.build());
+ result.setSignatureResult(signatureChecker.getSignatureResult());
result.setDecryptionResult(
new OpenPgpDecryptionResult(OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED));
result.setDecryptionMetadata(metadata);
@@ -1059,30 +887,28 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
OperationLog log = new OperationLog();
- OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
-
updateProgress(R.string.progress_processing_signature, 0, 100);
InputStream detachedSigIn = new ByteArrayInputStream(input.getDetachedSignature());
detachedSigIn = PGPUtil.getDecoderStream(detachedSigIn);
- JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(detachedSigIn);
+ JcaSkipMarkerPGPObjectFactory pgpFact = new JcaSkipMarkerPGPObjectFactory(detachedSigIn);
- PGPSignatureList sigList;
Object o = pgpFact.nextObject();
if (o instanceof PGPCompressedData) {
PGPCompressedData c1 = (PGPCompressedData) o;
- pgpFact = new JcaPGPObjectFactory(c1.getDataStream());
- sigList = (PGPSignatureList) pgpFact.nextObject();
- } else if (o instanceof PGPSignatureList) {
- sigList = (PGPSignatureList) o;
- } else {
+ pgpFact = new JcaSkipMarkerPGPObjectFactory(c1.getDataStream());
+ o = pgpFact.nextObject();
+ }
+
+ PgpSignatureChecker signatureChecker = new PgpSignatureChecker(mProviderHelper);
+
+ if ( ! signatureChecker.initializeSignature(o, log, indent+1)) {
log.add(LogType.MSG_DC_ERROR_INVALID_DATA, 0);
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
}
- PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder, log, indent);
+ if (signatureChecker.isInitialized()) {
- if (signature != null) {
updateProgress(R.string.progress_reading_data, 60, 100);
ProgressScaler progressScaler = new ProgressScaler(mProgressable, 60, 90, 100);
@@ -1097,7 +923,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
}
// update signature buffer if signature is also present
- signature.update(buffer, 0, length);
+ signatureChecker.updateSignatureData(buffer, 0, length);
alreadyWritten += length;
if (wholeSize > 0) {
@@ -1108,105 +934,28 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
}
progressScaler.setProgress((int) progress, 100);
}
- // TODO: slow annealing to fake a progress?
}
updateProgress(R.string.progress_verifying_signature, 90, 100);
log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent);
- // Verify signature and check binding signatures
- boolean validSignature = signature.verify();
- if (validSignature) {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1);
- } else {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1);
- }
-
- // check for insecure hash algorithms
- if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) {
- log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1);
- signatureResultBuilder.setInsecure(true);
- }
+ signatureChecker.verifySignature(log, indent);
- signatureResultBuilder.setValidSignature(validSignature);
}
updateProgress(R.string.progress_done, 100, 100);
log.add(LogType.MSG_DC_OK, indent);
+ // TODO return metadata object?
+
DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log);
- result.setSignatureResult(signatureResultBuilder.build());
+ result.setSignatureResult(signatureChecker.getSignatureResult());
result.setDecryptionResult(
new OpenPgpDecryptionResult(OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED));
return result;
}
- private PGPSignature processPGPSignatureList(
- PGPSignatureList sigList, OpenPgpSignatureResultBuilder signatureResultBuilder,
- OperationLog log, int indent)
- throws PGPException {
- CanonicalizedPublicKeyRing signingRing = null;
- CanonicalizedPublicKey signingKey = null;
- int signatureIndex = -1;
-
- // go through all signatures
- // and find out for which signature we have a key in our database
- for (int i = 0; i < sigList.size(); ++i) {
- try {
- long sigKeyId = sigList.get(i).getKeyID();
- signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
- KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
- );
- signingKey = signingRing.getPublicKey(sigKeyId);
- signatureIndex = i;
- } catch (ProviderHelper.NotFoundException e) {
- Log.d(Constants.TAG, "key not found, trying next signature...");
- }
- }
-
- PGPSignature signature = null;
-
- if (signingKey != null) {
- // key found in our database!
- signature = sigList.get(signatureIndex);
-
- signatureResultBuilder.initValid(signingRing, signingKey);
-
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
- new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey());
- } else {
- // no key in our database -> return "unknown pub key" status including the first key id
- if (!sigList.isEmpty()) {
- signatureResultBuilder.setSignatureAvailable(true);
- signatureResultBuilder.setKnownKey(false);
- signatureResultBuilder.setKeyId(sigList.get(0).getKeyID());
- }
- }
-
- // check for insecure signing key
- // TODO: checks on signingRing ?
- if (signingKey != null && ! PgpSecurityConstants.isSecureKey(signingKey)) {
- log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1);
- signatureResultBuilder.setInsecure(true);
- }
-
- return signature;
- }
-
- /**
- * Mostly taken from ClearSignedFileProcessor in Bouncy Castle
- */
- private static void processLine(PGPSignature sig, byte[] line)
- throws SignatureException {
- int length = getLengthWithoutWhiteSpace(line);
- if (length > 0) {
- sig.update(line, 0, length);
- }
- }
-
private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn)
throws IOException {
bOut.reset();
@@ -1272,22 +1021,21 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
return b == '\r' || b == '\n';
}
- private static int getLengthWithoutWhiteSpace(byte[] line) {
- int end = line.length - 1;
-
- while (end >= 0 && isWhiteSpace(line[end])) {
- end--;
- }
-
- return end + 1;
- }
-
- private static boolean isWhiteSpace(byte b) {
- return b == '\r' || b == '\n' || b == '\t' || b == ' ';
- }
-
private static byte[] getLineSeparator() {
String nl = System.getProperty("line.separator");
return nl.getBytes();
}
+
+ /// Convenience method - Trivially checks if a byte array matches the bytes of a plain text string
+ // Assumes data.length >= needle.length()
+ static boolean matchesPrefix(byte[] data, String needle) {
+ byte[] needleBytes = needle.getBytes();
+ for (int i = 0; i < needle.length(); i++) {
+ if (data[i] != needleBytes[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
index e8d1d3111..016651c3b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java
@@ -18,23 +18,15 @@
package org.sufficientlysecure.keychain.pgp;
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
import android.support.annotation.NonNull;
import android.text.TextUtils;
import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.Preferences;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.security.SecureRandom;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
public class PgpHelper {
@@ -51,35 +43,6 @@ public class PgpHelper {
Pattern.DOTALL);
/**
- * Deletes file securely by overwriting it with random data before deleting it.
- * <p/>
- * TODO: Does this really help on flash storage?
- *
- * @throws IOException
- */
- public static void deleteFileSecurely(Context context, Progressable progressable, File file)
- throws IOException {
- long length = file.length();
- SecureRandom random = new SecureRandom();
- RandomAccessFile raf = new RandomAccessFile(file, "rws");
- raf.seek(0);
- raf.getFilePointer();
- byte[] data = new byte[1 << 16];
- int pos = 0;
- String msg = context.getString(R.string.progress_deleting_securely, file.getName());
- while (pos < length) {
- if (progressable != null) {
- progressable.setProgress(msg, (int) (100 * pos / length), 100);
- }
- random.nextBytes(data);
- raf.write(data);
- pos += data.length;
- }
- raf.close();
- file.delete();
- }
-
- /**
* Fixing broken PGP MESSAGE Strings coming from GMail/AOSP Mail
*/
public static String fixPgpMessage(String message) {
@@ -117,7 +80,7 @@ public class PgpHelper {
}
}
- public static String getPgpContent(@NonNull CharSequence input) {
+ public static String getPgpMessageContent(@NonNull CharSequence input) {
Log.dEscaped(Constants.TAG, "input: " + input);
Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(input);
@@ -141,4 +104,18 @@ public class PgpHelper {
}
}
+ public static String getPgpKeyContent(@NonNull CharSequence input) {
+ Log.dEscaped(Constants.TAG, "input: " + input);
+
+ Matcher matcher = PgpHelper.PGP_PUBLIC_KEY.matcher(input);
+ if (matcher.matches()) {
+ String text = matcher.group(1);
+ text = fixPgpMessage(text);
+
+ Log.dEscaped(Constants.TAG, "input fixed: " + text);
+ return text;
+ }
+ return null;
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
index 6f156c201..59b840054 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -171,8 +171,8 @@ public class PgpKeyOperation {
log.add(LogType.MSG_CR_ERROR_NO_KEYSIZE, indent);
return null;
}
- if (add.mKeySize < 512) {
- log.add(LogType.MSG_CR_ERROR_KEYSIZE_512, indent);
+ if (add.mKeySize < 2048) {
+ log.add(LogType.MSG_CR_ERROR_KEYSIZE_2048, indent);
return null;
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java
index cbd8ce47a..7ad7b4d0f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java
@@ -79,8 +79,8 @@ public class PgpSecurityConstants {
*/
private static HashSet<Integer> sHashAlgorithmsWhitelist = new HashSet<>(Arrays.asList(
// MD5: broken
- // SHA1: broken
- // RIPEMD160: same security properties as SHA1
+ HashAlgorithmTags.SHA1, // TODO: disable when SHA256 is widely deployed
+ HashAlgorithmTags.RIPEMD160, // same security properties as SHA1, TODO: disable when SHA256 is widely deployed
// DOUBLE_SHA: not used widely
// MD2: not used widely
// TIGER_192: not used widely
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java
index 36d1a07cb..c2c6234eb 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInputParcel.java
@@ -44,6 +44,7 @@ public class PgpSignEncryptInputParcel implements Parcelable {
protected boolean mDetachedSignature = false;
protected boolean mHiddenRecipients = false;
protected boolean mIntegrityProtected = true;
+ protected boolean mAddBackupHeader = false;
public PgpSignEncryptInputParcel() {
@@ -70,6 +71,7 @@ public class PgpSignEncryptInputParcel implements Parcelable {
mDetachedSignature = source.readInt() == 1;
mHiddenRecipients = source.readInt() == 1;
mIntegrityProtected = source.readInt() == 1;
+ mAddBackupHeader = source.readInt() == 1;
}
@Override
@@ -100,6 +102,7 @@ public class PgpSignEncryptInputParcel implements Parcelable {
dest.writeInt(mDetachedSignature ? 1 : 0);
dest.writeInt(mHiddenRecipients ? 1 : 0);
dest.writeInt(mIntegrityProtected ? 1 : 0);
+ dest.writeInt(mAddBackupHeader ? 1 : 0);
}
public String getCharset() {
@@ -244,6 +247,15 @@ public class PgpSignEncryptInputParcel implements Parcelable {
return this;
}
+ public PgpSignEncryptInputParcel setAddBackupHeader(boolean addBackupHeader) {
+ this.mAddBackupHeader = addBackupHeader;
+ return this;
+ }
+
+ public boolean isAddBackupHeader() {
+ return mAddBackupHeader;
+ }
+
public boolean isHiddenRecipients() {
return mHiddenRecipients;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java
index 29b2ef727..45641b33a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java
@@ -53,6 +53,7 @@ import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.ProgressScaler;
+import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
@@ -148,6 +149,10 @@ public class PgpSignEncryptOperation extends BaseOperation {
if (input.getCharset() != null) {
armorOut.setHeader("Charset", input.getCharset());
}
+ // add proprietary header to indicate that this is a key backup
+ if (input.isAddBackupHeader()) {
+ armorOut.setHeader("BackupVersion", "1");
+ }
out = armorOut;
} else {
out = outputStream;
@@ -316,6 +321,8 @@ public class PgpSignEncryptOperation extends BaseOperation {
ArmoredOutputStream detachedArmorOut = null;
BCPGOutputStream detachedBcpgOut = null;
+ long opTime, startTime = System.currentTimeMillis();
+
try {
if (enableEncryption) {
@@ -361,7 +368,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
long alreadyWritten = 0;
int length;
byte[] buffer = new byte[1 << 16];
- InputStream in = inputData.getInputStream();
+ InputStream in = new BufferedInputStream(inputData.getInputStream());
while ((length = in.read(buffer)) > 0) {
pOut.write(buffer, 0, length);
@@ -389,7 +396,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
// write -----BEGIN PGP SIGNED MESSAGE-----
armorOut.beginClearText(input.getSignatureHashAlgorithm());
- InputStream in = inputData.getInputStream();
+ InputStream in = new BufferedInputStream(inputData.getInputStream());
final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
// update signature buffer with first line
@@ -421,7 +428,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
updateProgress(R.string.progress_signing, 8, 100);
log.add(LogType.MSG_PSE_SIGNING_DETACHED, indent);
- InputStream in = inputData.getInputStream();
+ InputStream in = new BufferedInputStream(inputData.getInputStream());
// handle output stream separately for detached signatures
detachedByteOut = new ByteArrayOutputStream();
@@ -458,7 +465,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
updateProgress(R.string.progress_signing, 8, 100);
log.add(LogType.MSG_PSE_SIGNING, indent);
- InputStream in = inputData.getInputStream();
+ InputStream in = new BufferedInputStream(inputData.getInputStream());
if (enableCompression) {
compressGen = new PGPCompressedDataGenerator(input.getCompressionAlgorithm());
@@ -491,9 +498,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
literalGen.close();
} else {
- pOut = null;
- // TODO: Is this log right?
- log.add(LogType.MSG_PSE_CLEARSIGN_ONLY, indent);
+ throw new AssertionError("cannot clearsign in non-ascii armored text, this is a bug!");
}
if (enableSignature) {
@@ -513,6 +518,10 @@ public class PgpSignEncryptOperation extends BaseOperation {
}
}
+ opTime = System.currentTimeMillis() -startTime;
+ Log.d(Constants.TAG, "sign/encrypt time taken: " + String.format("%.2f",
+ opTime / 1000.0) + "s");
+
// closing outputs
// NOTE: closing needs to be done in the correct order!
if (encryptionOut != null) {
@@ -556,6 +565,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
log.add(LogType.MSG_PSE_OK, indent);
PgpSignEncryptResult result = new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_OK, log);
+ result.mOperationTime = opTime;
if (detachedByteOut != null) {
try {
detachedByteOut.flush();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignatureChecker.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignatureChecker.java
new file mode 100644
index 000000000..ed5566bc1
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignatureChecker.java
@@ -0,0 +1,344 @@
+package org.sufficientlysecure.keychain.pgp;
+
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.SignatureException;
+
+import org.openintents.openpgp.OpenPgpSignatureResult;
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPOnePassSignature;
+import org.spongycastle.openpgp.PGPOnePassSignatureList;
+import org.spongycastle.openpgp.PGPSignature;
+import org.spongycastle.openpgp.PGPSignatureList;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.util.Log;
+
+
+/** This class is used to track the state of a single signature verification.
+ *
+ *
+ */
+class PgpSignatureChecker {
+
+ OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
+
+ private CanonicalizedPublicKey signingKey;
+
+ private int signatureIndex;
+ PGPOnePassSignature onePassSignature;
+ PGPSignature signature;
+
+ ProviderHelper mProviderHelper;
+
+ PgpSignatureChecker(ProviderHelper providerHelper) {
+ mProviderHelper = providerHelper;
+ }
+
+ boolean initializeSignature(Object dataChunk, OperationLog log, int indent) throws PGPException {
+
+ if (!(dataChunk instanceof PGPSignatureList)) {
+ return false;
+ }
+
+ PGPSignatureList sigList = (PGPSignatureList) dataChunk;
+ findAvailableSignature(sigList);
+
+ if (signingKey != null) {
+
+ // key found in our database!
+ signatureResultBuilder.initValid(signingKey);
+
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
+ new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey());
+ checkKeySecurity(log, indent);
+
+
+ } else if (!sigList.isEmpty()) {
+
+ signatureResultBuilder.setSignatureAvailable(true);
+ signatureResultBuilder.setKnownKey(false);
+ signatureResultBuilder.setKeyId(sigList.get(0).getKeyID());
+
+ }
+
+ return true;
+
+ }
+
+ boolean initializeOnePassSignature(Object dataChunk, OperationLog log, int indent) throws PGPException {
+
+ if (!(dataChunk instanceof PGPOnePassSignatureList)) {
+ return false;
+ }
+
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE, indent + 1);
+
+ PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
+ findAvailableSignature(sigList);
+
+ if (signingKey != null) {
+
+ // key found in our database!
+ signatureResultBuilder.initValid(signingKey);
+
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
+ new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ onePassSignature.init(contentVerifierBuilderProvider, signingKey.getPublicKey());
+
+ checkKeySecurity(log, indent);
+
+ } else if (!sigList.isEmpty()) {
+
+ signatureResultBuilder.setSignatureAvailable(true);
+ signatureResultBuilder.setKnownKey(false);
+ signatureResultBuilder.setKeyId(sigList.get(0).getKeyID());
+
+ }
+
+ return true;
+
+ }
+
+ private void checkKeySecurity(OperationLog log, int indent) {
+ // TODO: checks on signingRing ?
+ if (!PgpSecurityConstants.isSecureKey(signingKey)) {
+ log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1);
+ signatureResultBuilder.setInsecure(true);
+ }
+ }
+
+ public boolean isInitialized() {
+ return signingKey != null;
+ }
+
+ private void findAvailableSignature(PGPOnePassSignatureList sigList) {
+ // go through all signatures (should be just one), make sure we have
+ // the key and it matches the one we’re looking for
+ for (int i = 0; i < sigList.size(); ++i) {
+ try {
+ long sigKeyId = sigList.get(i).getKeyID();
+ CanonicalizedPublicKeyRing signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
+ KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
+ );
+ CanonicalizedPublicKey keyCandidate = signingRing.getPublicKey(sigKeyId);
+ if ( ! keyCandidate.canSign()) {
+ continue;
+ }
+ signatureIndex = i;
+ signingKey = keyCandidate;
+ onePassSignature = sigList.get(i);
+ return;
+ } catch (ProviderHelper.NotFoundException e) {
+ Log.d(Constants.TAG, "key not found, trying next signature...");
+ }
+ }
+ }
+
+ public void findAvailableSignature(PGPSignatureList sigList) {
+ // go through all signatures (should be just one), make sure we have
+ // the key and it matches the one we’re looking for
+ for (int i = 0; i < sigList.size(); ++i) {
+ try {
+ long sigKeyId = sigList.get(i).getKeyID();
+ CanonicalizedPublicKeyRing signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
+ KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
+ );
+ CanonicalizedPublicKey keyCandidate = signingRing.getPublicKey(sigKeyId);
+ if ( ! keyCandidate.canSign()) {
+ continue;
+ }
+ signatureIndex = i;
+ signingKey = keyCandidate;
+ signature = sigList.get(i);
+ return;
+ } catch (ProviderHelper.NotFoundException e) {
+ Log.d(Constants.TAG, "key not found, trying next signature...");
+ }
+ }
+ }
+
+ public void updateSignatureWithCleartext(byte[] clearText) throws IOException, SignatureException {
+
+ InputStream sigIn = new BufferedInputStream(new ByteArrayInputStream(clearText));
+
+ ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream();
+
+ int lookAhead = readInputLine(outputBuffer, sigIn);
+
+ processLine(signature, outputBuffer.toByteArray());
+
+ while (lookAhead != -1) {
+ lookAhead = readInputLine(outputBuffer, lookAhead, sigIn);
+
+ signature.update((byte) '\r');
+ signature.update((byte) '\n');
+
+ processLine(signature, outputBuffer.toByteArray());
+ }
+
+ }
+
+ public void updateSignatureData(byte[] buf, int off, int len) {
+ if (signature != null) {
+ signature.update(buf, off, len);
+ } else if (onePassSignature != null) {
+ onePassSignature.update(buf, off, len);
+ }
+ }
+
+ void verifySignature(OperationLog log, int indent) throws PGPException {
+
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent);
+
+ // Verify signature
+ boolean validSignature = signature.verify();
+ if (validSignature) {
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1);
+ } else {
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1);
+ }
+
+ // check for insecure hash algorithms
+ if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) {
+ log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1);
+ signatureResultBuilder.setInsecure(true);
+ }
+
+ signatureResultBuilder.setValidSignature(validSignature);
+
+ }
+
+ boolean verifySignatureOnePass(Object o, OperationLog log, int indent) throws PGPException {
+
+ if (!(o instanceof PGPSignatureList)) {
+ log.add(LogType.MSG_DC_ERROR_NO_SIGNATURE, indent);
+ return false;
+ }
+ PGPSignatureList signatureList = (PGPSignatureList) o;
+ if (signatureList.size() <= signatureIndex) {
+ log.add(LogType.MSG_DC_ERROR_NO_SIGNATURE, indent);
+ return false;
+ }
+
+ // PGPOnePassSignature and PGPSignature packets are "bracketed",
+ // so we need to take the last-minus-index'th element here
+ PGPSignature messageSignature = signatureList.get(signatureList.size() - 1 - signatureIndex);
+
+ // Verify signature
+ boolean validSignature = onePassSignature.verify(messageSignature);
+ if (validSignature) {
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1);
+ } else {
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1);
+ }
+
+ // check for insecure hash algorithms
+ if (!PgpSecurityConstants.isSecureHashAlgorithm(onePassSignature.getHashAlgorithm())) {
+ log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1);
+ signatureResultBuilder.setInsecure(true);
+ }
+
+ signatureResultBuilder.setValidSignature(validSignature);
+
+ return true;
+
+ }
+
+ public byte[] getSigningFingerprint() {
+ return signingKey.getFingerprint();
+ }
+
+ public OpenPgpSignatureResult getSignatureResult() {
+ return signatureResultBuilder.build();
+ }
+
+ /**
+ * Mostly taken from ClearSignedFileProcessor in Bouncy Castle
+ */
+
+ private static void processLine(PGPSignature sig, byte[] line)
+ throws SignatureException {
+ int length = getLengthWithoutWhiteSpace(line);
+ if (length > 0) {
+ sig.update(line, 0, length);
+ }
+ }
+
+ private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn)
+ throws IOException {
+ bOut.reset();
+
+ int lookAhead = -1;
+ int ch;
+
+ while ((ch = fIn.read()) >= 0) {
+ bOut.write(ch);
+ if (ch == '\r' || ch == '\n') {
+ lookAhead = readPastEOL(bOut, ch, fIn);
+ break;
+ }
+ }
+
+ return lookAhead;
+ }
+
+ private static int readInputLine(ByteArrayOutputStream bOut, int lookAhead, InputStream fIn)
+ throws IOException {
+ bOut.reset();
+
+ int ch = lookAhead;
+
+ do {
+ bOut.write(ch);
+ if (ch == '\r' || ch == '\n') {
+ lookAhead = readPastEOL(bOut, ch, fIn);
+ break;
+ }
+ } while ((ch = fIn.read()) >= 0);
+
+ if (ch < 0) {
+ lookAhead = -1;
+ }
+
+ return lookAhead;
+ }
+
+ private static int readPastEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn)
+ throws IOException {
+ int lookAhead = fIn.read();
+
+ if (lastCh == '\r' && lookAhead == '\n') {
+ bOut.write(lookAhead);
+ lookAhead = fIn.read();
+ }
+
+ return lookAhead;
+ }
+
+ private static int getLengthWithoutWhiteSpace(byte[] line) {
+ int end = line.length - 1;
+
+ while (end >= 0 && isWhiteSpace(line[end])) {
+ end--;
+ }
+
+ return end + 1;
+ }
+
+ private static boolean isWhiteSpace(byte b) {
+ return b == '\r' || b == '\n' || b == '\t' || b == ' ';
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
index ca98882d8..c967a5abc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -18,6 +18,23 @@
package org.sufficientlysecure.keychain.pgp;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.TreeSet;
+
import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
import org.spongycastle.bcpg.SignatureSubpacketTags;
@@ -43,23 +60,6 @@ import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Utf8Util;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.TimeZone;
-import java.util.TreeSet;
-
/** Wrapper around PGPKeyRing class, to be constructed from bytes.
*
* This class and its relatives UncachedPublicKey and UncachedSecretKey are
@@ -78,12 +78,13 @@ import java.util.TreeSet;
* @see org.sufficientlysecure.keychain.pgp.UncachedSecretKey
*
*/
-@SuppressWarnings("unchecked")
-public class UncachedKeyRing implements Serializable {
+public class UncachedKeyRing {
final PGPKeyRing mRing;
final boolean mIsSecret;
+ private static final int CANONICALIZE_MAX_USER_IDS = 100;
+
UncachedKeyRing(PGPKeyRing ring) {
mRing = ring;
mIsSecret = ring instanceof PGPSecretKeyRing;
@@ -457,11 +458,15 @@ public class UncachedKeyRing implements Serializable {
// check for duplicate user ids
if (processedUserIds.contains(userId)) {
- log.add(LogType.MSG_KC_UID_DUP,
- indent, userId);
+ log.add(LogType.MSG_KC_UID_DUP, indent, userId);
// strip out the first found user id with this name
modified = PGPPublicKey.removeCertification(modified, rawUserId);
}
+ if (processedUserIds.size() > CANONICALIZE_MAX_USER_IDS) {
+ log.add(LogType.MSG_KC_UID_TOO_MANY, indent, userId);
+ // strip out the user id
+ modified = PGPPublicKey.removeCertification(modified, rawUserId);
+ }
processedUserIds.add(userId);
PGPSignature selfCert = null;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
index d7fb738fc..752c13007 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
@@ -54,7 +54,7 @@ import java.io.IOException;
*/
public class KeychainDatabase extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "openkeychain.db";
- private static final int DATABASE_VERSION = 12;
+ private static final int DATABASE_VERSION = 14;
static Boolean apgHack = false;
private Context mContext;
@@ -79,7 +79,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
private static final String CREATE_KEYRINGS_SECRET =
"CREATE TABLE IF NOT EXISTS keyrings_secret ("
+ KeyRingsColumns.MASTER_KEY_ID + " INTEGER PRIMARY KEY,"
- + KeyRingsColumns.KEY_RING_DATA + " BLOB,"
+ + KeyRingsColumns.KEY_RING_DATA + " BLOB, "
+ "FOREIGN KEY(" + KeyRingsColumns.MASTER_KEY_ID + ") "
+ "REFERENCES keyrings_public(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE"
+ ")";
@@ -220,6 +220,13 @@ public class KeychainDatabase extends SQLiteOpenHelper {
db.execSQL(CREATE_API_APPS);
db.execSQL(CREATE_API_APPS_ACCOUNTS);
db.execSQL(CREATE_API_APPS_ALLOWED_KEYS);
+
+ db.execSQL("CREATE INDEX keys_by_rank ON keys (" + KeysColumns.RANK + ");");
+ db.execSQL("CREATE INDEX uids_by_rank ON user_packets (" + UserPacketsColumns.RANK + ", "
+ + UserPacketsColumns.USER_ID + ", " + UserPacketsColumns.MASTER_KEY_ID + ");");
+ db.execSQL("CREATE INDEX verified_certs ON certs ("
+ + CertsColumns.VERIFIED + ", " + CertsColumns.MASTER_KEY_ID + ");");
+
}
@Override
@@ -291,11 +298,14 @@ public class KeychainDatabase extends SQLiteOpenHelper {
db.execSQL("DELETE FROM api_accounts WHERE key_id BETWEEN 0 AND 3");
case 12:
db.execSQL(CREATE_UPDATE_KEYS);
- if (oldVersion == 10) {
- // no consolidate if we are updating from 10, we're just here for
- // the api_accounts fix and the new update keys table
- return;
- }
+ case 13:
+ // do nothing here, just consolidate
+ case 14:
+ db.execSQL("CREATE INDEX keys_by_rank ON keys (" + KeysColumns.RANK + ");");
+ db.execSQL("CREATE INDEX uids_by_rank ON user_packets (" + UserPacketsColumns.RANK + ", "
+ + UserPacketsColumns.USER_ID + ", " + UserPacketsColumns.MASTER_KEY_ID + ");");
+ db.execSQL("CREATE INDEX verified_certs ON certs ("
+ + CertsColumns.VERIFIED + ", " + CertsColumns.MASTER_KEY_ID + ");");
}
@@ -306,6 +316,17 @@ public class KeychainDatabase extends SQLiteOpenHelper {
mContext.getApplicationContext().startActivity(consolidateIntent);
}
+ @Override
+ public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // Downgrade is ok for the debug version, makes it easier to work with branches
+ if (Constants.DEBUG) {
+ return;
+ }
+ // NOTE: downgrading the database is explicitly not allowed to prevent
+ // someone from exploiting old bugs to export the database
+ throw new RuntimeException("Downgrading the database is not allowed!");
+ }
+
/** This method tries to import data from a provided database.
*
* The sole assumptions made on this db are that there is a key_rings table
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
index d722fa9e7..104343074 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
@@ -303,14 +303,14 @@ public class KeychainProvider extends ContentProvider {
projectionMap.put(KeyRings.FINGERPRINT, Tables.KEYS + "." + Keys.FINGERPRINT);
projectionMap.put(KeyRings.USER_ID, Tables.USER_PACKETS + "." + UserPackets.USER_ID);
projectionMap.put(KeyRings.HAS_DUPLICATE_USER_ID,
- "(SELECT COUNT (*) FROM " + Tables.USER_PACKETS + " AS dups"
+ "(EXISTS (SELECT * FROM " + Tables.USER_PACKETS + " AS dups"
+ " WHERE dups." + UserPackets.MASTER_KEY_ID
+ " != " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
+ " AND dups." + UserPackets.RANK + " = 0"
+ " AND dups." + UserPackets.USER_ID
+ " = "+ Tables.USER_PACKETS + "." + UserPackets.USER_ID
- + ") AS " + KeyRings.HAS_DUPLICATE_USER_ID);
- projectionMap.put(KeyRings.VERIFIED, KeyRings.VERIFIED);
+ + ")) AS " + KeyRings.HAS_DUPLICATE_USER_ID);
+ projectionMap.put(KeyRings.VERIFIED, Tables.CERTS + "." + Certs.VERIFIED);
projectionMap.put(KeyRings.PUBKEY_DATA,
Tables.KEY_RINGS_PUBLIC + "." + KeyRingData.KEY_RING_DATA
+ " AS " + KeyRings.PUBKEY_DATA);
@@ -319,10 +319,8 @@ public class KeychainProvider extends ContentProvider {
+ " AS " + KeyRings.PRIVKEY_DATA);
projectionMap.put(KeyRings.HAS_SECRET, Tables.KEYS + "." + KeyRings.HAS_SECRET);
projectionMap.put(KeyRings.HAS_ANY_SECRET,
- "(EXISTS (SELECT * FROM " + Tables.KEY_RINGS_SECRET
- + " WHERE " + Tables.KEY_RINGS_SECRET + "." + KeyRingData.MASTER_KEY_ID
- + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
- + ")) AS " + KeyRings.HAS_ANY_SECRET);
+ "(" + Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NOT NULL)" +
+ " AS " + KeyRings.HAS_ANY_SECRET);
projectionMap.put(KeyRings.HAS_ENCRYPT,
"kE." + Keys.KEY_ID + " AS " + KeyRings.HAS_ENCRYPT);
projectionMap.put(KeyRings.HAS_SIGN,
@@ -363,7 +361,7 @@ public class KeychainProvider extends ContentProvider {
+ " = "
+ Tables.KEY_RINGS_PUBLIC + "." + KeyRingData.MASTER_KEY_ID
+ ")" : "")
- + (plist.contains(KeyRings.PRIVKEY_DATA) ?
+ + (plist.contains(KeyRings.PRIVKEY_DATA) || plist.contains(KeyRings.HAS_ANY_SECRET) ?
" LEFT JOIN " + Tables.KEY_RINGS_SECRET + " ON ("
+ Tables.KEYS + "." + Keys.MASTER_KEY_ID
+ " = "
@@ -712,20 +710,45 @@ public class KeychainProvider extends ContentProvider {
}
SQLiteDatabase db = getDb().getReadableDatabase();
+
Cursor cursor = qb.query(db, projection, selection, selectionArgs, groupBy, having, orderBy);
if (cursor != null) {
// Tell the cursor what uri to watch, so it knows when its source data changes
cursor.setNotificationUri(getContext().getContentResolver(), uri);
}
+ Log.d(Constants.TAG,
+ "Query: " + qb.buildQuery(projection, selection, null, null, orderBy, null));
+
if (Constants.DEBUG && Constants.DEBUG_LOG_DB_QUERIES) {
- Log.d(Constants.TAG,
- "Query: "
- + qb.buildQuery(projection, selection, selectionArgs, null, null,
- orderBy, null));
Log.d(Constants.TAG, "Cursor: " + DatabaseUtils.dumpCursorToString(cursor));
}
+ if (Constants.DEBUG && Constants.DEBUG_EXPLAIN_QUERIES) {
+ String rawQuery = qb.buildQuery(projection, selection, groupBy, having, orderBy, null);
+ Cursor explainCursor = db.rawQuery("EXPLAIN QUERY PLAN " + rawQuery, selectionArgs);
+
+ // this is a debugging feature, we can be a little careless
+ explainCursor.moveToFirst();
+
+ StringBuilder line = new StringBuilder();
+ for (int i = 0; i < explainCursor.getColumnCount(); i++) {
+ line.append(explainCursor.getColumnName(i)).append(", ");
+ }
+ Log.d(Constants.TAG, line.toString());
+
+ while (!explainCursor.isAfterLast()) {
+ line = new StringBuilder();
+ for (int i = 0; i < explainCursor.getColumnCount(); i++) {
+ line.append(explainCursor.getString(i)).append(", ");
+ }
+ Log.d(Constants.TAG, line.toString());
+ explainCursor.moveToNext();
+ }
+
+ explainCursor.close();
+ }
+
return cursor;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index a6823d3ac..375775ff1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -62,7 +62,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
-import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeys;
import org.sufficientlysecure.keychain.remote.AccountSettings;
import org.sufficientlysecure.keychain.remote.AppSettings;
@@ -968,7 +967,7 @@ public class ProviderHelper {
// If we have an expected fingerprint, make sure it matches
if (expectedFingerprint != null) {
- if (!canPublicRing.containsSubkey(expectedFingerprint)) {
+ if (!canPublicRing.containsBoundSubkey(expectedFingerprint)) {
log(LogType.MSG_IP_FINGERPRINT_ERROR);
return new SaveKeyringResult(SaveKeyringResult.RESULT_ERROR, mLog, null);
} else {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryFileProvider.java
index 67f2c36bc..68963d595 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryStorageProvider.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/TemporaryFileProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
@@ -29,7 +29,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
-import android.provider.OpenableColumns;
+import android.provider.MediaStore;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.DatabaseUtil;
@@ -39,18 +39,20 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* TemporaryStorageProvider stores decrypted files inside the app's cache directory previously to
* sharing them with other applications.
- *
+ * <p/>
* Security:
* - It is writable by OpenKeychain only (see Manifest), but exported for reading files
* - It uses UUIDs as identifiers which makes predicting files from outside impossible
* - Querying a number of files is not allowed, only querying single files
* -> You can only open a file if you know the Uri containing the precise UUID, this Uri is only
* revealed when the user shares a decrypted file with another app.
- *
+ * <p/>
* Why is support lib's FileProvider not used?
* Because granting Uri permissions temporarily does not work correctly. See
* - https://code.google.com/p/android/issues/detail?id=76683
@@ -59,30 +61,36 @@ import java.util.UUID;
* - http://stackoverflow.com/q/18249007
* - Comments at http://www.blogc.at/2014/03/23/share-private-files-with-other-apps-fileprovider/
*/
-public class TemporaryStorageProvider extends ContentProvider {
+public class TemporaryFileProvider extends ContentProvider {
private static final String DB_NAME = "tempstorage.db";
private static final String TABLE_FILES = "files";
- private static final String COLUMN_ID = "id";
- private static final String COLUMN_NAME = "name";
- private static final String COLUMN_TIME = "time";
- private static final String COLUMN_TYPE = "mimetype";
- public static final String AUTHORITY = Constants.TEMPSTORAGE_AUTHORITY;
+ public static final String AUTHORITY = Constants.TEMP_FILE_PROVIDER_AUTHORITY;
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
private static final int DB_VERSION = 3;
- private static File cacheDir;
+ interface TemporaryFileColumns {
+ String COLUMN_UUID = "id";
+ String COLUMN_NAME = "name";
+ String COLUMN_TIME = "time";
+ String COLUMN_TYPE = "mimetype";
+ }
+
+ private static final String TEMP_FILES_DIR = "temp";
+ private static File tempFilesDir;
+
+ private static Pattern UUID_PATTERN = Pattern.compile("[a-fA-F0-9-]+");
public static Uri createFile(Context context, String targetName, String mimeType) {
ContentValues contentValues = new ContentValues();
- contentValues.put(COLUMN_NAME, targetName);
- contentValues.put(COLUMN_TYPE, mimeType);
+ contentValues.put(TemporaryFileColumns.COLUMN_NAME, targetName);
+ contentValues.put(TemporaryFileColumns.COLUMN_TYPE, mimeType);
return context.getContentResolver().insert(CONTENT_URI, contentValues);
}
public static Uri createFile(Context context, String targetName) {
ContentValues contentValues = new ContentValues();
- contentValues.put(COLUMN_NAME, targetName);
+ contentValues.put(TemporaryFileColumns.COLUMN_NAME, targetName);
return context.getContentResolver().insert(CONTENT_URI, contentValues);
}
@@ -93,13 +101,16 @@ public class TemporaryStorageProvider extends ContentProvider {
public static int setMimeType(Context context, Uri uri, String mimetype) {
ContentValues values = new ContentValues();
- values.put(COLUMN_TYPE, mimetype);
+ values.put(TemporaryFileColumns.COLUMN_TYPE, mimetype);
return context.getContentResolver().update(uri, values, null, null);
}
public static int cleanUp(Context context) {
- return context.getContentResolver().delete(CONTENT_URI, COLUMN_TIME + "< ?",
- new String[]{Long.toString(System.currentTimeMillis() - Constants.TEMPFILE_TTL)});
+ return context.getContentResolver().delete(
+ CONTENT_URI,
+ TemporaryFileColumns.COLUMN_TIME + "< ?",
+ new String[]{Long.toString(System.currentTimeMillis() - Constants.TEMPFILE_TTL)}
+ );
}
private class TemporaryStorageDatabase extends SQLiteOpenHelper {
@@ -111,10 +122,10 @@ public class TemporaryStorageProvider extends ContentProvider {
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_FILES + " (" +
- COLUMN_ID + " TEXT PRIMARY KEY, " +
- COLUMN_NAME + " TEXT, " +
- COLUMN_TYPE + " TEXT, " +
- COLUMN_TIME + " INTEGER" +
+ TemporaryFileColumns.COLUMN_UUID + " TEXT PRIMARY KEY, " +
+ TemporaryFileColumns.COLUMN_NAME + " TEXT, " +
+ TemporaryFileColumns.COLUMN_TYPE + " TEXT, " +
+ TemporaryFileColumns.COLUMN_TIME + " INTEGER" +
");");
}
@@ -126,12 +137,12 @@ public class TemporaryStorageProvider extends ContentProvider {
case 1:
db.execSQL("DROP TABLE IF EXISTS files");
db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_FILES + " (" +
- COLUMN_ID + " TEXT PRIMARY KEY, " +
- COLUMN_NAME + " TEXT, " +
- COLUMN_TIME + " INTEGER" +
+ TemporaryFileColumns.COLUMN_UUID + " TEXT PRIMARY KEY, " +
+ TemporaryFileColumns.COLUMN_NAME + " TEXT, " +
+ TemporaryFileColumns.COLUMN_TIME + " INTEGER" +
");");
case 2:
- db.execSQL("ALTER TABLE files ADD COLUMN " + COLUMN_TYPE + " TEXT");
+ db.execSQL("ALTER TABLE files ADD COLUMN " + TemporaryFileColumns.COLUMN_TYPE + " TEXT");
}
}
}
@@ -147,14 +158,19 @@ public class TemporaryStorageProvider extends ContentProvider {
}
private File getFile(String id) {
- return new File(cacheDir, "temp/" + id);
+ Matcher m = UUID_PATTERN.matcher(id);
+ if (!m.matches()) {
+ throw new SecurityException("Can only open temporary files with UUIDs!");
+ }
+
+ return new File(tempFilesDir, id);
}
@Override
public boolean onCreate() {
db = new TemporaryStorageDatabase(getContext());
- cacheDir = getContext().getCacheDir();
- return new File(cacheDir, "temp").mkdirs();
+ tempFilesDir = new File(getContext().getCacheDir(), TEMP_FILES_DIR);
+ return tempFilesDir.mkdirs();
}
@Override
@@ -163,27 +179,24 @@ public class TemporaryStorageProvider extends ContentProvider {
throw new SecurityException("Listing temporary files is not allowed, only querying single files.");
}
- Log.d(Constants.TAG, "being asked for file " + uri);
-
File file;
try {
file = getFile(uri);
- if (file.exists()) {
- Log.e(Constants.TAG, "already exists");
- }
} catch (FileNotFoundException e) {
Log.e(Constants.TAG, "file not found!");
return null;
}
- Cursor fileName = db.getReadableDatabase().query(TABLE_FILES, new String[]{COLUMN_NAME}, COLUMN_ID + "=?",
+ Cursor fileName = db.getReadableDatabase().query(TABLE_FILES,
+ new String[]{TemporaryFileColumns.COLUMN_NAME},
+ TemporaryFileColumns.COLUMN_UUID + "=?",
new String[]{uri.getLastPathSegment()}, null, null, null);
if (fileName != null) {
if (fileName.moveToNext()) {
MatrixCursor cursor = new MatrixCursor(new String[]{
- OpenableColumns.DISPLAY_NAME,
- OpenableColumns.SIZE,
- "_data"
+ MediaStore.MediaColumns.DISPLAY_NAME,
+ MediaStore.MediaColumns.SIZE,
+ MediaStore.MediaColumns.DATA,
});
cursor.newRow()
.add(fileName.getString(0))
@@ -200,7 +213,8 @@ public class TemporaryStorageProvider extends ContentProvider {
@Override
public String getType(Uri uri) {
Cursor cursor = db.getReadableDatabase().query(TABLE_FILES,
- new String[]{COLUMN_TYPE}, COLUMN_ID + "=?",
+ new String[]{TemporaryFileColumns.COLUMN_TYPE},
+ TemporaryFileColumns.COLUMN_UUID + "=?",
new String[]{uri.getLastPathSegment()}, null, null, null);
if (cursor != null) {
try {
@@ -227,11 +241,11 @@ public class TemporaryStorageProvider extends ContentProvider {
@Override
public Uri insert(Uri uri, ContentValues values) {
- if (!values.containsKey(COLUMN_TIME)) {
- values.put(COLUMN_TIME, System.currentTimeMillis());
+ if (!values.containsKey(TemporaryFileColumns.COLUMN_TIME)) {
+ values.put(TemporaryFileColumns.COLUMN_TIME, System.currentTimeMillis());
}
String uuid = UUID.randomUUID().toString();
- values.put(COLUMN_ID, uuid);
+ values.put(TemporaryFileColumns.COLUMN_UUID, uuid);
int insert = (int) db.getWritableDatabase().insert(TABLE_FILES, null, values);
if (insert == -1) {
Log.e(Constants.TAG, "Insert failed!");
@@ -252,10 +266,10 @@ public class TemporaryStorageProvider extends ContentProvider {
return 0;
}
- selection = DatabaseUtil.concatenateWhere(selection, COLUMN_ID + "=?");
+ selection = DatabaseUtil.concatenateWhere(selection, TemporaryFileColumns.COLUMN_UUID + "=?");
selectionArgs = DatabaseUtil.appendSelectionArgs(selectionArgs, new String[]{uri.getLastPathSegment()});
- Cursor files = db.getReadableDatabase().query(TABLE_FILES, new String[]{COLUMN_ID}, selection,
+ Cursor files = db.getReadableDatabase().query(TABLE_FILES, new String[]{TemporaryFileColumns.COLUMN_UUID}, selection,
selectionArgs, null, null, null);
if (files != null) {
while (files.moveToNext()) {
@@ -269,19 +283,18 @@ public class TemporaryStorageProvider extends ContentProvider {
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- if (values.size() != 1 || !values.containsKey(COLUMN_TYPE)) {
+ if (values.size() != 1 || !values.containsKey(TemporaryFileColumns.COLUMN_TYPE)) {
throw new UnsupportedOperationException("Update supported only for type field!");
}
if (selection != null || selectionArgs != null) {
throw new UnsupportedOperationException("Update supported only for plain uri!");
}
return db.getWritableDatabase().update(TABLE_FILES, values,
- COLUMN_ID + " = ?", new String[]{uri.getLastPathSegment()});
+ TemporaryFileColumns.COLUMN_UUID + " = ?", new String[]{uri.getLastPathSegment()});
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
- Log.d(Constants.TAG, "openFile");
return openFileHelper(uri, mode);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
index e7709e58e..b810f5a6a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -25,6 +25,7 @@ import android.net.Uri;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
@@ -34,13 +35,15 @@ import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpMetadata;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.openintents.openpgp.util.OpenPgpApi;
+import org.spongycastle.bcpg.ArmoredOutputStream;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel;
import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
-import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants;
-import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation;
+import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants;
import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInputParcel;
import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
@@ -238,10 +241,8 @@ public class OpenPgpService extends RemoteService {
PendingIntent.FLAG_CANCEL_CURRENT);
}
- private Intent signImpl(Intent data, ParcelFileDescriptor input,
- ParcelFileDescriptor output, boolean cleartextSign) {
- InputStream is = null;
- OutputStream os = null;
+ private Intent signImpl(Intent data, InputStream inputStream,
+ OutputStream outputStream, boolean cleartextSign) {
try {
boolean asciiArmor = cleartextSign || data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
@@ -277,14 +278,13 @@ public class OpenPgpService extends RemoteService {
}
// Get Input- and OutputStream from ParcelFileDescriptor
- is = new ParcelFileDescriptor.AutoCloseInputStream(input);
- if (cleartextSign) {
+ if (!cleartextSign) {
// output stream only needed for cleartext signatures,
// detached signatures are returned as extra
- os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
+ outputStream = null;
}
- long inputLength = is.available();
- InputData inputData = new InputData(is, inputLength);
+ long inputLength = inputStream.available();
+ InputData inputData = new InputData(inputStream, inputLength);
CryptoInputParcel inputParcel = CryptoInputParcelCacheService.getCryptoInputParcel(this, data);
if (inputParcel == null) {
@@ -298,7 +298,7 @@ public class OpenPgpService extends RemoteService {
// execute PGP operation!
PgpSignEncryptOperation pse = new PgpSignEncryptOperation(this, new ProviderHelper(getContext()), null);
- PgpSignEncryptResult pgpResult = pse.execute(pseInput, inputParcel, inputData, os);
+ PgpSignEncryptResult pgpResult = pse.execute(pseInput, inputParcel, inputData, outputStream);
if (pgpResult.isPending()) {
@@ -330,28 +330,11 @@ public class OpenPgpService extends RemoteService {
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result;
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- Log.e(Constants.TAG, "IOException when closing InputStream", e);
- }
- }
- if (os != null) {
- try {
- os.close();
- } catch (IOException e) {
- Log.e(Constants.TAG, "IOException when closing OutputStream", e);
- }
- }
}
}
- private Intent encryptAndSignImpl(Intent data, ParcelFileDescriptor input,
- ParcelFileDescriptor output, boolean sign) {
- InputStream is = null;
- OutputStream os = null;
+ private Intent encryptAndSignImpl(Intent data, InputStream inputStream,
+ OutputStream outputStream, boolean sign) {
try {
boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
String originalFilename = data.getStringExtra(OpenPgpApi.EXTRA_ORIGINAL_FILENAME);
@@ -383,13 +366,9 @@ public class OpenPgpService extends RemoteService {
}
}
- // build InputData and write into OutputStream
- // Get Input- and OutputStream from ParcelFileDescriptor
- is = new ParcelFileDescriptor.AutoCloseInputStream(input);
- os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
-
- long inputLength = is.available();
- InputData inputData = new InputData(is, inputLength, originalFilename);
+ // TODO this is not correct!
+ long inputLength = inputStream.available();
+ InputData inputData = new InputData(inputStream, inputLength, originalFilename);
PgpSignEncryptInputParcel pseInput = new PgpSignEncryptInputParcel();
pseInput.setEnableAsciiArmorOutput(asciiArmor)
@@ -455,7 +434,7 @@ public class OpenPgpService extends RemoteService {
PgpSignEncryptOperation op = new PgpSignEncryptOperation(this, new ProviderHelper(getContext()), null);
// execute PGP operation!
- PgpSignEncryptResult pgpResult = op.execute(pseInput, inputParcel, inputData, os);
+ PgpSignEncryptResult pgpResult = op.execute(pseInput, inputParcel, inputData, outputStream);
if (pgpResult.isPending()) {
RequiredInputParcel requiredInput = pgpResult.getRequiredInputParcel();
@@ -482,37 +461,15 @@ public class OpenPgpService extends RemoteService {
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result;
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- Log.e(Constants.TAG, "IOException when closing InputStream", e);
- }
- }
- if (os != null) {
- try {
- os.close();
- } catch (IOException e) {
- Log.e(Constants.TAG, "IOException when closing OutputStream", e);
- }
- }
}
}
- private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor inputDescriptor,
- ParcelFileDescriptor output, boolean decryptMetadataOnly) {
- InputStream inputStream = null;
- OutputStream outputStream = null;
+ private Intent decryptAndVerifyImpl(Intent data, InputStream inputStream,
+ OutputStream outputStream, boolean decryptMetadataOnly) {
try {
- // Get Input- and OutputStream from ParcelFileDescriptor
- inputStream = new ParcelFileDescriptor.AutoCloseInputStream(inputDescriptor);
-
// output is optional, e.g., for verifying detached signatures
- if (decryptMetadataOnly || output == null) {
+ if (decryptMetadataOnly) {
outputStream = null;
- } else {
- outputStream = new ParcelFileDescriptor.AutoCloseOutputStream(output);
}
String currentPkg = getCurrentCallingPackage();
@@ -538,6 +495,7 @@ public class OpenPgpService extends RemoteService {
PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(this, mProviderHelper, null);
+ // TODO this is not correct!
long inputLength = inputStream.available();
InputData inputData = new InputData(inputStream, inputLength);
@@ -604,6 +562,7 @@ public class OpenPgpService extends RemoteService {
// case RESULT_NOT_ENCRYPTED, but a signature, fallback to deprecated signatureOnly variable
if (decryptionResult.getResult() == OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED
&& signatureResult.getResult() != OpenPgpSignatureResult.RESULT_NO_SIGNATURE) {
+ // noinspection deprecation, TODO
signatureResult.setSignatureOnly(true);
}
@@ -665,35 +624,40 @@ public class OpenPgpService extends RemoteService {
result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result;
- } finally {
- if (inputStream != null) {
- try {
- inputStream.close();
- } catch (IOException e) {
- Log.e(Constants.TAG, "IOException when closing InputStream", e);
- }
- }
- if (outputStream != null) {
- try {
- outputStream.close();
- } catch (IOException e) {
- Log.e(Constants.TAG, "IOException when closing OutputStream", e);
- }
- }
}
}
- private Intent getKeyImpl(Intent data) {
+ private Intent getKeyImpl(Intent data, OutputStream outputStream) {
try {
long masterKeyId = data.getLongExtra(OpenPgpApi.EXTRA_KEY_ID, 0);
try {
// try to find key, throws NotFoundException if not in db!
- mProviderHelper.getCanonicalizedPublicKeyRing(masterKeyId);
+ CanonicalizedPublicKeyRing keyRing =
+ mProviderHelper.getCanonicalizedPublicKeyRing(masterKeyId);
Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
+
+ boolean requestedKeyData = outputStream != null;
+ if (requestedKeyData) {
+ boolean requestAsciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, false);
+
+ try {
+ if (requestAsciiArmor) {
+ outputStream = new ArmoredOutputStream(outputStream);
+ }
+ keyRing.encode(outputStream);
+ } finally {
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException when closing OutputStream", e);
+ }
+ }
+ }
+
// also return PendingIntent that opens the key view activity
result.putExtra(OpenPgpApi.RESULT_INTENT, getShowKeyPendingIntent(masterKeyId));
@@ -821,7 +785,7 @@ public class OpenPgpService extends RemoteService {
OpenPgpError error = new OpenPgpError
(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!\n"
+ "used API version: " + data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) + "\n"
- + "supported API versions: " + supportedVersions.toString());
+ + "supported API versions: " + supportedVersions);
result.putExtra(OpenPgpApi.RESULT_ERROR, error);
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result;
@@ -850,68 +814,88 @@ public class OpenPgpService extends RemoteService {
return mBinder;
}
+ @Nullable
+ protected Intent executeInternal(
+ @NonNull Intent data,
+ @Nullable ParcelFileDescriptor input,
+ @Nullable ParcelFileDescriptor output) {
- protected Intent executeInternal(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output) {
- try {
- Intent errorResult = checkRequirements(data);
- if (errorResult != null) {
- return errorResult;
- }
+ OutputStream outputStream =
+ (output != null) ? new ParcelFileDescriptor.AutoCloseOutputStream(output) : null;
+ InputStream inputStream =
+ (input != null) ? new ParcelFileDescriptor.AutoCloseInputStream(input) : null;
- String action = data.getAction();
- switch (action) {
- case OpenPgpApi.ACTION_CLEARTEXT_SIGN: {
- return signImpl(data, input, output, true);
- }
- case OpenPgpApi.ACTION_SIGN: {
- // DEPRECATED: same as ACTION_CLEARTEXT_SIGN
- Log.w(Constants.TAG, "You are using a deprecated API call, please use ACTION_CLEARTEXT_SIGN instead of ACTION_SIGN!");
- return signImpl(data, input, output, true);
- }
- case OpenPgpApi.ACTION_DETACHED_SIGN: {
- return signImpl(data, input, output, false);
- }
- case OpenPgpApi.ACTION_ENCRYPT: {
- return encryptAndSignImpl(data, input, output, false);
- }
- case OpenPgpApi.ACTION_SIGN_AND_ENCRYPT: {
- return encryptAndSignImpl(data, input, output, true);
- }
- case OpenPgpApi.ACTION_DECRYPT_VERIFY: {
- return decryptAndVerifyImpl(data, input, output, false);
- }
- case OpenPgpApi.ACTION_DECRYPT_METADATA: {
- return decryptAndVerifyImpl(data, input, output, true);
- }
- case OpenPgpApi.ACTION_GET_SIGN_KEY_ID: {
- return getSignKeyIdImpl(data);
- }
- case OpenPgpApi.ACTION_GET_KEY_IDS: {
- return getKeyIdsImpl(data);
- }
- case OpenPgpApi.ACTION_GET_KEY: {
- return getKeyImpl(data);
- }
- default: {
- return null;
- }
- }
+ try {
+ return executeInternalWithStreams(data, inputStream, outputStream);
} finally {
// always close input and output file descriptors even in error cases
- if (input != null) {
+ if (inputStream != null) {
try {
- input.close();
+ inputStream.close();
} catch (IOException e) {
Log.e(Constants.TAG, "IOException when closing input ParcelFileDescriptor", e);
}
}
- if (output != null) {
+ if (outputStream != null) {
try {
- output.close();
+ outputStream.close();
} catch (IOException e) {
Log.e(Constants.TAG, "IOException when closing output ParcelFileDescriptor", e);
}
}
}
}
+
+ @Nullable
+ protected Intent executeInternalWithStreams(
+ @NonNull Intent data,
+ @Nullable InputStream inputStream,
+ @Nullable OutputStream outputStream) {
+
+ Intent errorResult = checkRequirements(data);
+ if (errorResult != null) {
+ return errorResult;
+ }
+
+ String action = data.getAction();
+ switch (action) {
+ case OpenPgpApi.ACTION_CLEARTEXT_SIGN: {
+ return signImpl(data, inputStream, outputStream, true);
+ }
+ case OpenPgpApi.ACTION_SIGN: {
+ // DEPRECATED: same as ACTION_CLEARTEXT_SIGN
+ Log.w(Constants.TAG, "You are using a deprecated API call, please use ACTION_CLEARTEXT_SIGN instead of ACTION_SIGN!");
+ return signImpl(data, inputStream, outputStream, true);
+ }
+ case OpenPgpApi.ACTION_DETACHED_SIGN: {
+ return signImpl(data, inputStream, outputStream, false);
+ }
+ case OpenPgpApi.ACTION_ENCRYPT: {
+ return encryptAndSignImpl(data, inputStream, outputStream, false);
+ }
+ case OpenPgpApi.ACTION_SIGN_AND_ENCRYPT: {
+ return encryptAndSignImpl(data, inputStream, outputStream, true);
+ }
+ case OpenPgpApi.ACTION_DECRYPT_VERIFY: {
+ return decryptAndVerifyImpl(data, inputStream, outputStream, false);
+ }
+ case OpenPgpApi.ACTION_DECRYPT_METADATA: {
+ return decryptAndVerifyImpl(data, inputStream, outputStream, true);
+ }
+ case OpenPgpApi.ACTION_GET_SIGN_KEY_ID: {
+ return getSignKeyIdImpl(data);
+ }
+ case OpenPgpApi.ACTION_GET_KEY_IDS: {
+ return getKeyIdsImpl(data);
+ }
+ case OpenPgpApi.ACTION_GET_KEY: {
+ return getKeyImpl(data, outputStream);
+ }
+ default: {
+ return null;
+ }
+ }
+
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/BackupKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/BackupKeyringParcel.java
new file mode 100644
index 000000000..3d9626934
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/BackupKeyringParcel.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.service;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.sufficientlysecure.keychain.util.Passphrase;
+
+
+public class BackupKeyringParcel implements Parcelable {
+ public Uri mCanonicalizedPublicKeyringUri;
+ public Passphrase mSymmetricPassphrase;
+
+ public boolean mExportSecret;
+ public long mMasterKeyIds[];
+ public Uri mOutputUri;
+
+ public BackupKeyringParcel(Passphrase symmetricPassphrase,
+ long[] masterKeyIds, boolean exportSecret, Uri outputUri) {
+ mSymmetricPassphrase = symmetricPassphrase;
+ mMasterKeyIds = masterKeyIds;
+ mExportSecret = exportSecret;
+ mOutputUri = outputUri;
+ }
+
+ protected BackupKeyringParcel(Parcel in) {
+ mCanonicalizedPublicKeyringUri = (Uri) in.readValue(Uri.class.getClassLoader());
+ mExportSecret = in.readByte() != 0x00;
+ mOutputUri = (Uri) in.readValue(Uri.class.getClassLoader());
+ mMasterKeyIds = in.createLongArray();
+ mSymmetricPassphrase = in.readParcelable(getClass().getClassLoader());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeValue(mCanonicalizedPublicKeyringUri);
+ dest.writeByte((byte) (mExportSecret ? 0x01 : 0x00));
+ dest.writeValue(mOutputUri);
+ dest.writeLongArray(mMasterKeyIds);
+ dest.writeParcelable(mSymmetricPassphrase, 0);
+ }
+
+ public static final Parcelable.Creator<BackupKeyringParcel> CREATOR = new Parcelable.Creator<BackupKeyringParcel>() {
+ @Override
+ public BackupKeyringParcel createFromParcel(Parcel in) {
+ return new BackupKeyringParcel(in);
+ }
+
+ @Override
+ public BackupKeyringParcel[] newArray(int size) {
+ return new BackupKeyringParcel[size];
+ }
+ };
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/BenchmarkInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/BenchmarkInputParcel.java
new file mode 100644
index 000000000..cfbdfefff
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/BenchmarkInputParcel.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.service;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+
+public class BenchmarkInputParcel implements Parcelable {
+
+ public BenchmarkInputParcel() {
+ }
+
+ protected BenchmarkInputParcel(Parcel in) {
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+
+ public static final Creator<BenchmarkInputParcel> CREATOR = new Creator<BenchmarkInputParcel>() {
+ @Override
+ public BenchmarkInputParcel createFromParcel(Parcel in) {
+ return new BenchmarkInputParcel(in);
+ }
+
+ @Override
+ public BenchmarkInputParcel[] newArray(int size) {
+ return new BenchmarkInputParcel[size];
+ }
+ };
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java
deleted file mode 100644
index 24c002bbd..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ExportKeyringParcel.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
- * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
- * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.service;
-
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
-
-public class ExportKeyringParcel implements Parcelable {
- public String mKeyserver;
- public Uri mCanonicalizedPublicKeyringUri;
- public UncachedKeyRing mUncachedKeyRing;
-
- public boolean mExportSecret;
- public long mMasterKeyIds[];
- public String mOutputFile;
- public Uri mOutputUri;
- public ExportType mExportType;
-
- public enum ExportType {
- UPLOAD_KEYSERVER,
- EXPORT_FILE,
- EXPORT_URI
- }
-
- public ExportKeyringParcel(String keyserver, Uri keyringUri) {
- mExportType = ExportType.UPLOAD_KEYSERVER;
- mKeyserver = keyserver;
- mCanonicalizedPublicKeyringUri = keyringUri;
- }
-
- public ExportKeyringParcel(String keyserver, UncachedKeyRing uncachedKeyRing) {
- mExportType = ExportType.UPLOAD_KEYSERVER;
- mKeyserver = keyserver;
- mUncachedKeyRing = uncachedKeyRing;
- }
-
- public ExportKeyringParcel(long[] masterKeyIds, boolean exportSecret, String outputFile) {
- mExportType = ExportType.EXPORT_FILE;
- mMasterKeyIds = masterKeyIds;
- mExportSecret = exportSecret;
- mOutputFile = outputFile;
- }
-
- @SuppressWarnings("unused") // TODO: is it used?
- public ExportKeyringParcel(long[] masterKeyIds, boolean exportSecret, Uri outputUri) {
- mExportType = ExportType.EXPORT_URI;
- mMasterKeyIds = masterKeyIds;
- mExportSecret = exportSecret;
- mOutputUri = outputUri;
- }
-
- protected ExportKeyringParcel(Parcel in) {
- mKeyserver = in.readString();
- mCanonicalizedPublicKeyringUri = (Uri) in.readValue(Uri.class.getClassLoader());
- mUncachedKeyRing = (UncachedKeyRing) in.readValue(UncachedKeyRing.class.getClassLoader());
- mExportSecret = in.readByte() != 0x00;
- mOutputFile = in.readString();
- mOutputUri = (Uri) in.readValue(Uri.class.getClassLoader());
- mExportType = (ExportType) in.readValue(ExportType.class.getClassLoader());
- mMasterKeyIds = in.createLongArray();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mKeyserver);
- dest.writeValue(mCanonicalizedPublicKeyringUri);
- dest.writeValue(mUncachedKeyRing);
- dest.writeByte((byte) (mExportSecret ? 0x01 : 0x00));
- dest.writeString(mOutputFile);
- dest.writeValue(mOutputUri);
- dest.writeValue(mExportType);
- dest.writeLongArray(mMasterKeyIds);
- }
-
- public static final Parcelable.Creator<ExportKeyringParcel> CREATOR = new Parcelable.Creator<ExportKeyringParcel>() {
- @Override
- public ExportKeyringParcel createFromParcel(Parcel in) {
- return new ExportKeyringParcel(in);
- }
-
- @Override
- public ExportKeyringParcel[] newArray(int size) {
- return new ExportKeyringParcel[size];
- }
- };
-} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java
index c7ac92eef..cf51e3b55 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java
@@ -29,17 +29,19 @@ import android.os.RemoteException;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.operations.BaseOperation;
+import org.sufficientlysecure.keychain.operations.BenchmarkOperation;
import org.sufficientlysecure.keychain.operations.CertifyOperation;
import org.sufficientlysecure.keychain.operations.ConsolidateOperation;
import org.sufficientlysecure.keychain.operations.DeleteOperation;
import org.sufficientlysecure.keychain.operations.EditKeyOperation;
-import org.sufficientlysecure.keychain.operations.ExportOperation;
+import org.sufficientlysecure.keychain.operations.BackupOperation;
import org.sufficientlysecure.keychain.operations.ImportOperation;
import org.sufficientlysecure.keychain.operations.KeybaseVerificationOperation;
import org.sufficientlysecure.keychain.operations.InputDataOperation;
import org.sufficientlysecure.keychain.operations.PromoteKeyOperation;
import org.sufficientlysecure.keychain.operations.RevokeOperation;
import org.sufficientlysecure.keychain.operations.SignEncryptOperation;
+import org.sufficientlysecure.keychain.operations.UploadOperation;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
@@ -124,14 +126,18 @@ public class KeychainService extends Service implements Progressable {
op = new PromoteKeyOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
} else if (inputParcel instanceof ImportKeyringParcel) {
op = new ImportOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
- } else if (inputParcel instanceof ExportKeyringParcel) {
- op = new ExportOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
+ } else if (inputParcel instanceof BackupKeyringParcel) {
+ op = new BackupOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
+ } else if (inputParcel instanceof UploadKeyringParcel) {
+ op = new UploadOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
} else if (inputParcel instanceof ConsolidateInputParcel) {
op = new ConsolidateOperation(outerThis, new ProviderHelper(outerThis), outerThis);
} else if (inputParcel instanceof KeybaseVerificationParcel) {
op = new KeybaseVerificationOperation(outerThis, new ProviderHelper(outerThis), outerThis);
} else if (inputParcel instanceof InputDataParcel) {
op = new InputDataOperation(outerThis, new ProviderHelper(outerThis), outerThis);
+ } else if (inputParcel instanceof BenchmarkInputParcel) {
+ op = new BenchmarkOperation(outerThis, new ProviderHelper(outerThis), outerThis);
} else {
throw new AssertionError("Unrecognized input parcel in KeychainService!");
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java
index 8aebae7aa..122eb6cf4 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java
@@ -59,11 +59,12 @@ public class KeyserverSyncAdapterService extends Service {
// time since last update after which a key should be updated again, in s
public static final long KEY_UPDATE_LIMIT =
Constants.DEBUG_KEYSERVER_SYNC ? 1 : TimeUnit.DAYS.toSeconds(7);
- // time by which a sync is postponed in case of a
+ // time by which a sync is postponed in case screen is on
public static final long SYNC_POSTPONE_TIME =
Constants.DEBUG_KEYSERVER_SYNC ? 30 * 1000 : TimeUnit.MINUTES.toMillis(5);
// Time taken by Orbot before a new circuit is created
- public static final int ORBOT_CIRCUIT_TIMEOUT = (int) TimeUnit.MINUTES.toMillis(10);
+ public static final int ORBOT_CIRCUIT_TIMEOUT_SECONDS =
+ Constants.DEBUG_KEYSERVER_SYNC ? 2 : (int) TimeUnit.MINUTES.toSeconds(10);
private static final String ACTION_IGNORE_TOR = "ignore_tor";
@@ -77,10 +78,14 @@ public class KeyserverSyncAdapterService extends Service {
@Override
public int onStartCommand(final Intent intent, int flags, final int startId) {
+ if (intent == null || intent.getAction() == null) {
+ // introduced due to https://github.com/open-keychain/open-keychain/issues/1573
+ return START_NOT_STICKY; // we can't act on this Intent and don't want it redelivered
+ }
switch (intent.getAction()) {
case ACTION_CANCEL: {
mCancelled.set(true);
- break;
+ return START_NOT_STICKY;
}
// the reason for the separation betweyeen SYNC_NOW and UPDATE_ALL is so that starting
// the sync directly from the notification is possible while the screen is on with
@@ -92,44 +97,47 @@ public class KeyserverSyncAdapterService extends Service {
Constants.PROVIDER_AUTHORITY,
new Bundle()
);
- break;
+ return START_NOT_STICKY;
}
case ACTION_UPDATE_ALL: {
// does not check for screen on/off
- asyncKeyUpdate(this, new CryptoInputParcel());
- break;
+ asyncKeyUpdate(this, new CryptoInputParcel(), startId);
+ // we depend on handleUpdateResult to call stopSelf when it is no longer necessary
+ // for the intent to be redelivered
+ return START_REDELIVER_INTENT;
}
case ACTION_IGNORE_TOR: {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT);
- asyncKeyUpdate(this, new CryptoInputParcel(ParcelableProxy.getForNoProxy()));
- break;
+ asyncKeyUpdate(this, new CryptoInputParcel(ParcelableProxy.getForNoProxy()),
+ startId);
+ // we depend on handleUpdateResult to call stopSelf when it is no longer necessary
+ // for the intent to be redelivered
+ return START_REDELIVER_INTENT;
}
case ACTION_START_ORBOT: {
- NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+ NotificationManager manager = (NotificationManager)
+ getSystemService(NOTIFICATION_SERVICE);
manager.cancel(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT);
+
Intent startOrbot = new Intent(this, OrbotRequiredDialogActivity.class);
startOrbot.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startOrbot.putExtra(OrbotRequiredDialogActivity.EXTRA_START_ORBOT, true);
+
Messenger messenger = new Messenger(
new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case OrbotRequiredDialogActivity.MESSAGE_ORBOT_STARTED: {
- asyncKeyUpdate(KeyserverSyncAdapterService.this,
- new CryptoInputParcel());
- break;
- }
- case OrbotRequiredDialogActivity.MESSAGE_ORBOT_IGNORE: {
- asyncKeyUpdate(KeyserverSyncAdapterService.this,
- new CryptoInputParcel(
- ParcelableProxy.getForNoProxy()));
+ startServiceWithUpdateAll();
break;
}
+ case OrbotRequiredDialogActivity.MESSAGE_ORBOT_IGNORE:
case OrbotRequiredDialogActivity.MESSAGE_DIALOG_CANCEL: {
- // just stop service
- stopSelf();
+ // not possible since we proceed to Orbot's Activity
+ // directly, by starting OrbotRequiredDialogActivity with
+ // EXTRA_START_ORBOT set to true
break;
}
}
@@ -138,13 +146,17 @@ public class KeyserverSyncAdapterService extends Service {
);
startOrbot.putExtra(OrbotRequiredDialogActivity.EXTRA_MESSENGER, messenger);
startActivity(startOrbot);
- break;
+ // since we return START_NOT_STICKY, we also postpone the sync as a backup in case
+ // the service is killed before OrbotRequiredDialogActivity can get back to us
+ postponeSync();
+ // if use START_REDELIVER_INTENT, we might annoy the user by repeatedly starting the
+ // Orbot Activity when our service is killed and restarted
+ return START_NOT_STICKY;
}
case ACTION_DISMISS_NOTIFICATION: {
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT);
- stopSelf(startId);
- break;
+ return START_NOT_STICKY;
}
}
return START_NOT_STICKY;
@@ -167,10 +179,7 @@ public class KeyserverSyncAdapterService extends Service {
boolean isScreenOn = pm.isScreenOn();
if (!isScreenOn) {
- Intent serviceIntent = new Intent(KeyserverSyncAdapterService.this,
- KeyserverSyncAdapterService.class);
- serviceIntent.setAction(ACTION_UPDATE_ALL);
- startService(serviceIntent);
+ startServiceWithUpdateAll();
} else {
postponeSync();
}
@@ -188,16 +197,24 @@ public class KeyserverSyncAdapterService extends Service {
return new KeyserverSyncAdapter().getSyncAdapterBinder();
}
- private void handleUpdateResult(ImportKeyResult result) {
+ /**
+ * Since we're returning START_REDELIVER_INTENT in onStartCommand, we need to remember to call
+ * stopSelf(int) to prevent the Intent from being redelivered if our work is already done
+ *
+ * @param result result of keyserver sync
+ * @param startId startId provided to the onStartCommand call which resulted in this sync
+ */
+ private void handleUpdateResult(ImportKeyResult result, final int startId) {
if (result.isPending()) {
+ Log.d(Constants.TAG, "Orbot required for sync but not running, attempting to start");
// result is pending due to Orbot not being started
// try to start it silently, if disabled show notifications
new OrbotHelper.SilentStartManager() {
@Override
protected void onOrbotStarted() {
// retry the update
- asyncKeyUpdate(KeyserverSyncAdapterService.this,
- new CryptoInputParcel());
+ startServiceWithUpdateAll();
+ stopSelf(startId); // startServiceWithUpdateAll will deliver a new Intent
}
@Override
@@ -207,16 +224,24 @@ public class KeyserverSyncAdapterService extends Service {
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT,
getOrbotNoification(KeyserverSyncAdapterService.this));
+ // further action on user interaction with notification, intent should not be
+ // redelivered, therefore:
+ stopSelf(startId);
}
}.startOrbotAndListen(this, false);
+ // if we're killed before we get a response from Orbot, we need the intent to be
+ // redelivered, so no stopSelf(int) here
} else if (isUpdateCancelled()) {
Log.d(Constants.TAG, "Keyserver sync cancelled, postponing by" + SYNC_POSTPONE_TIME
+ "ms");
postponeSync();
+ // postponeSync creates a new intent, so we don't need this to be redelivered
+ stopSelf(startId);
} else {
Log.d(Constants.TAG, "Keyserver sync completed: Updated: " + result.mUpdatedKeys
+ " Failed: " + result.mBadKeys);
- stopSelf();
+ // key sync completed successfully, we can stop
+ stopSelf(startId);
}
}
@@ -234,12 +259,12 @@ public class KeyserverSyncAdapterService extends Service {
}
private void asyncKeyUpdate(final Context context,
- final CryptoInputParcel cryptoInputParcel) {
+ final CryptoInputParcel cryptoInputParcel, final int startId) {
new Thread(new Runnable() {
@Override
public void run() {
ImportKeyResult result = updateKeysFromKeyserver(context, cryptoInputParcel);
- handleUpdateResult(result);
+ handleUpdateResult(result, startId);
}
}).start();
}
@@ -278,7 +303,6 @@ public class KeyserverSyncAdapterService extends Service {
);
}
-
/**
* will perform a staggered update of user's keys using delays to ensure new Tor circuits, as
* performed by parcimonie. Relevant issue and method at:
@@ -290,17 +314,31 @@ public class KeyserverSyncAdapterService extends Service {
CryptoInputParcel cryptoInputParcel) {
Log.d(Constants.TAG, "Starting staggered update");
// final int WEEK_IN_SECONDS = (int) TimeUnit.DAYS.toSeconds(7);
+ // we are limiting our randomness to ORBOT_CIRCUIT_TIMEOUT_SECONDS for now
final int WEEK_IN_SECONDS = 0;
+
ImportOperation.KeyImportAccumulator accumulator
= new ImportOperation.KeyImportAccumulator(keyList.size(), null);
+
+ // so that the first key can be updated without waiting. This is so that there isn't a
+ // large gap between a "Start Orbot" notification and the next key update
+ boolean first = true;
+
for (ParcelableKeyRing keyRing : keyList) {
int waitTime;
int staggeredTime = new Random().nextInt(1 + 2 * (WEEK_IN_SECONDS / keyList.size()));
- if (staggeredTime >= ORBOT_CIRCUIT_TIMEOUT) {
+ if (staggeredTime >= ORBOT_CIRCUIT_TIMEOUT_SECONDS) {
waitTime = staggeredTime;
} else {
- waitTime = ORBOT_CIRCUIT_TIMEOUT + new Random().nextInt(ORBOT_CIRCUIT_TIMEOUT);
+ waitTime = ORBOT_CIRCUIT_TIMEOUT_SECONDS
+ + new Random().nextInt(1 + ORBOT_CIRCUIT_TIMEOUT_SECONDS);
+ }
+
+ if (first) {
+ waitTime = 0;
+ first = false;
}
+
Log.d(Constants.TAG, "Updating key with fingerprint " + keyRing.mExpectedFingerprint +
" with a wait time of " + waitTime + "s");
try {
@@ -362,13 +400,15 @@ public class KeyserverSyncAdapterService extends Service {
);
ArrayList<Long> ignoreMasterKeyIds = new ArrayList<>();
- while (updatedKeysCursor.moveToNext()) {
+ while (updatedKeysCursor != null && updatedKeysCursor.moveToNext()) {
long masterKeyId = updatedKeysCursor.getLong(INDEX_UPDATED_KEYS_MASTER_KEY_ID);
Log.d(Constants.TAG, "Keyserver sync: Ignoring {" + masterKeyId + "} last updated at {"
+ updatedKeysCursor.getLong(INDEX_LAST_UPDATED) + "}s");
ignoreMasterKeyIds.add(masterKeyId);
}
- updatedKeysCursor.close();
+ if (updatedKeysCursor != null) {
+ updatedKeysCursor.close();
+ }
// 2. Make a list of public keys which should be updated
final int INDEX_MASTER_KEY_ID = 0;
@@ -413,7 +453,7 @@ public class KeyserverSyncAdapterService extends Service {
/**
* will cancel an update already in progress. We send an Intent to cancel it instead of simply
- * modifying a static variable sync the service is running in a process that is different from
+ * modifying a static variable since the service is running in a process that is different from
* the default application process where the UI code runs.
*
* @param context used to send an Intent to the service requesting cancellation.
@@ -491,6 +531,12 @@ public class KeyserverSyncAdapterService extends Service {
}
}
+ private void startServiceWithUpdateAll() {
+ Intent serviceIntent = new Intent(this, KeyserverSyncAdapterService.class);
+ serviceIntent.setAction(ACTION_UPDATE_ALL);
+ this.startService(serviceIntent);
+ }
+
// from de.azapps.mirakel.helper.Helpers from https://github.com/MirakelX/mirakel-android
private Bitmap getBitmap(int resId, Context context) {
int mLargeIconWidth = (int) context.getResources().getDimension(
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
index 5d04317b3..df29a388f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -256,14 +256,6 @@ public class PassphraseCacheService extends Service {
SecretKeyType keyType = keyRing.getSecretKeyType(subKeyId);
switch (keyType) {
- case DIVERT_TO_CARD:
- if (Preferences.getPreferences(this).useDefaultYubiKeyPin()) {
- Log.d(Constants.TAG, "PassphraseCacheService: Using default YubiKey PIN: 123456");
- return new Passphrase("123456"); // default YubiKey PIN, see http://www.yubico.com/2012/12/yubikey-neo-openpgp/
- } else {
- Log.d(Constants.TAG, "PassphraseCacheService: NOT using default YubiKey PIN");
- break;
- }
case PASSPHRASE_EMPTY:
return new Passphrase("");
case UNAVAILABLE:
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/UploadKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/UploadKeyringParcel.java
new file mode 100644
index 000000000..0a14f3dc6
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/UploadKeyringParcel.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.service;
+
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+
+public class UploadKeyringParcel implements Parcelable {
+ public String mKeyserver;
+
+ public final Long mMasterKeyId;
+ public final byte[] mUncachedKeyringBytes;
+
+ public UploadKeyringParcel(String keyserver, long masterKeyId) {
+ mKeyserver = keyserver;
+ mMasterKeyId = masterKeyId;
+ mUncachedKeyringBytes = null;
+ }
+
+ public UploadKeyringParcel(String keyserver, byte[] uncachedKeyringBytes) {
+ mKeyserver = keyserver;
+ mMasterKeyId = null;
+ mUncachedKeyringBytes = uncachedKeyringBytes;
+ }
+
+ protected UploadKeyringParcel(Parcel in) {
+ mKeyserver = in.readString();
+ mMasterKeyId = in.readInt() != 0 ? in.readLong() : null;
+ mUncachedKeyringBytes = in.createByteArray();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mKeyserver);
+ if (mMasterKeyId != null) {
+ dest.writeInt(1);
+ dest.writeLong(mMasterKeyId);
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeByteArray(mUncachedKeyringBytes);
+ }
+
+ public static final Creator<UploadKeyringParcel> CREATOR = new Creator<UploadKeyringParcel>() {
+ @Override
+ public UploadKeyringParcel createFromParcel(Parcel in) {
+ return new UploadKeyringParcel(in);
+ }
+
+ @Override
+ public UploadKeyringParcel[] newArray(int size) {
+ return new UploadKeyringParcel[size];
+ }
+ };
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java
index 0d8569fe6..849418905 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/CryptoInputParcel.java
@@ -23,6 +23,7 @@ import android.os.Parcelable;
import org.sufficientlysecure.keychain.util.ParcelableProxy;
import org.sufficientlysecure.keychain.util.Passphrase;
+import java.net.Proxy;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.HashMap;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java
index e4dac3227..1f99836ea 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/RequiredInputParcel.java
@@ -14,8 +14,8 @@ import java.util.Date;
public class RequiredInputParcel implements Parcelable {
public enum RequiredInputType {
- PASSPHRASE, PASSPHRASE_SYMMETRIC, NFC_SIGN, NFC_DECRYPT, NFC_MOVE_KEY_TO_CARD, ENABLE_ORBOT,
- UPLOAD_FAIL_RETRY
+ PASSPHRASE, PASSPHRASE_SYMMETRIC, BACKUP_CODE, NFC_SIGN, NFC_DECRYPT,
+ NFC_MOVE_KEY_TO_CARD, NFC_RESET_CARD, ENABLE_ORBOT, UPLOAD_FAIL_RETRY,
}
public Date mSignatureTime;
@@ -100,6 +100,11 @@ public class RequiredInputParcel implements Parcelable {
new byte[][] { encryptedSessionKey }, null, null, masterKeyId, subKeyId);
}
+ public static RequiredInputParcel createNfcReset() {
+ return new RequiredInputParcel(RequiredInputType.NFC_RESET_CARD,
+ null, null, null, null, null);
+ }
+
public static RequiredInputParcel createRequiredSignPassphrase(
long masterKeyId, long subKeyId, Date signatureTime) {
return new RequiredInputParcel(RequiredInputType.PASSPHRASE,
@@ -117,6 +122,11 @@ public class RequiredInputParcel implements Parcelable {
null, null, null, null, null);
}
+ public static RequiredInputParcel createRequiredBackupCode() {
+ return new RequiredInputParcel(RequiredInputType.BACKUP_CODE,
+ null, null, null, null, null);
+ }
+
public static RequiredInputParcel createRequiredPassphrase(
RequiredInputParcel req) {
return new RequiredInputParcel(RequiredInputType.PASSPHRASE,
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupActivity.java
new file mode 100644
index 000000000..ff120c9b5
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.sufficientlysecure.keychain.ui;
+
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.view.MenuItem;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.base.BaseActivity;
+
+
+public class BackupActivity extends BaseActivity {
+
+ public static final String EXTRA_MASTER_KEY_IDS = "master_key_ids";
+ public static final String EXTRA_SECRET = "export_secret";
+
+ @Override
+ protected void initLayout() {
+ setContentView(R.layout.backup_activity);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // noinspection ConstantConditions, we know this activity has an action bar
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+
+ if (savedInstanceState == null) {
+ Intent intent = getIntent();
+ boolean exportSecret = intent.getBooleanExtra(EXTRA_SECRET, false);
+ long[] masterKeyIds = intent.getLongArrayExtra(EXTRA_MASTER_KEY_IDS);
+
+ Fragment frag = BackupCodeFragment.newInstance(masterKeyIds, exportSecret);
+
+ FragmentManager fragMan = getSupportFragmentManager();
+ fragMan.beginTransaction()
+ .setCustomAnimations(0, 0)
+ .replace(R.id.content_frame, frag)
+ .commit();
+ }
+
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ FragmentManager fragMan = getSupportFragmentManager();
+ // pop from back stack, or if nothing was on there finish activity
+ if ( ! fragMan.popBackStackImmediate()) {
+ finish();
+ }
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeFragment.java
new file mode 100644
index 000000000..8afdb5f94
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupCodeFragment.java
@@ -0,0 +1,543 @@
+/*
+ * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.SecureRandom;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Random;
+
+import android.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentManager.OnBackStackChangedListener;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.operations.results.ExportResult;
+import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
+import org.sufficientlysecure.keychain.service.BackupKeyringParcel;
+import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment;
+import org.sufficientlysecure.keychain.ui.util.Notify;
+import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
+import org.sufficientlysecure.keychain.ui.util.Notify.Style;
+import org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator;
+import org.sufficientlysecure.keychain.util.FileHelper;
+import org.sufficientlysecure.keychain.util.Passphrase;
+
+public class BackupCodeFragment extends CryptoOperationFragment<BackupKeyringParcel, ExportResult>
+ implements OnBackStackChangedListener {
+
+ public static final String ARG_BACKUP_CODE = "backup_code";
+ public static final String BACK_STACK_INPUT = "state_display";
+ public static final String ARG_EXPORT_SECRET = "export_secret";
+ public static final String ARG_MASTER_KEY_IDS = "master_key_ids";
+
+ public static final String ARG_CURRENT_STATE = "current_state";
+
+ public static final int REQUEST_SAVE = 1;
+ public static final String ARG_BACK_STACK = "back_stack";
+
+ // argument variables
+ private boolean mExportSecret;
+ private long[] mMasterKeyIds;
+ String mBackupCode;
+
+ private EditText[] mCodeEditText;
+ private ToolableViewAnimator mStatusAnimator, mTitleAnimator, mCodeFieldsAnimator;
+
+ private Integer mBackStackLevel;
+
+ private Uri mCachedBackupUri;
+ private boolean mShareNotSave;
+
+ public static BackupCodeFragment newInstance(long[] masterKeyIds, boolean exportSecret) {
+ BackupCodeFragment frag = new BackupCodeFragment();
+
+ Bundle args = new Bundle();
+ args.putString(ARG_BACKUP_CODE, generateRandomCode());
+ args.putLongArray(ARG_MASTER_KEY_IDS, masterKeyIds);
+ args.putBoolean(ARG_EXPORT_SECRET, exportSecret);
+ frag.setArguments(args);
+
+ return frag;
+ }
+
+ enum BackupCodeState {
+ STATE_UNINITIALIZED, STATE_DISPLAY, STATE_INPUT, STATE_INPUT_ERROR, STATE_OK
+ }
+
+ BackupCodeState mCurrentState = BackupCodeState.STATE_UNINITIALIZED;
+
+ void switchState(BackupCodeState state, boolean animate) {
+
+ switch (state) {
+ case STATE_UNINITIALIZED:
+ throw new AssertionError("can't switch to uninitialized state, this is a bug!");
+
+ case STATE_DISPLAY:
+ mTitleAnimator.setDisplayedChild(0, animate);
+ mStatusAnimator.setDisplayedChild(0, animate);
+ mCodeFieldsAnimator.setDisplayedChild(0, animate);
+
+ break;
+
+ case STATE_INPUT:
+ mTitleAnimator.setDisplayedChild(1, animate);
+ mStatusAnimator.setDisplayedChild(1, animate);
+ mCodeFieldsAnimator.setDisplayedChild(1, animate);
+
+ for (EditText editText : mCodeEditText) {
+ editText.setText("");
+ }
+
+ pushBackStackEntry();
+
+ break;
+
+ case STATE_INPUT_ERROR: {
+ mTitleAnimator.setDisplayedChild(1, false);
+ mStatusAnimator.setDisplayedChild(2, animate);
+ mCodeFieldsAnimator.setDisplayedChild(1, false);
+
+ hideKeyboard();
+
+ if (animate) {
+ @ColorInt int black = mCodeEditText[0].getCurrentTextColor();
+ @ColorInt int red = getResources().getColor(R.color.android_red_dark);
+ animateFlashText(mCodeEditText, black, red, false);
+ }
+
+ break;
+ }
+
+ case STATE_OK: {
+ mTitleAnimator.setDisplayedChild(2, animate);
+ mStatusAnimator.setDisplayedChild(3, animate);
+ mCodeFieldsAnimator.setDisplayedChild(1, false);
+
+ hideKeyboard();
+
+ for (EditText editText : mCodeEditText) {
+ editText.setEnabled(false);
+ }
+
+ @ColorInt int green = getResources().getColor(R.color.android_green_dark);
+ if (animate) {
+ @ColorInt int black = mCodeEditText[0].getCurrentTextColor();
+ animateFlashText(mCodeEditText, black, green, true);
+ } else {
+ for (TextView textView : mCodeEditText) {
+ textView.setTextColor(green);
+ }
+ }
+
+ popBackStackNoAction();
+
+ break;
+ }
+
+ }
+
+ mCurrentState = state;
+
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.backup_code_fragment, container, false);
+
+ Bundle args = getArguments();
+ mBackupCode = args.getString(ARG_BACKUP_CODE);
+ mMasterKeyIds = args.getLongArray(ARG_MASTER_KEY_IDS);
+ mExportSecret = args.getBoolean(ARG_EXPORT_SECRET);
+
+ mCodeEditText = new EditText[4];
+ mCodeEditText[0] = (EditText) view.findViewById(R.id.backup_code_1);
+ mCodeEditText[1] = (EditText) view.findViewById(R.id.backup_code_2);
+ mCodeEditText[2] = (EditText) view.findViewById(R.id.backup_code_3);
+ mCodeEditText[3] = (EditText) view.findViewById(R.id.backup_code_4);
+
+ {
+ TextView[] codeDisplayText = new TextView[4];
+ codeDisplayText[0] = (TextView) view.findViewById(R.id.backup_code_display_1);
+ codeDisplayText[1] = (TextView) view.findViewById(R.id.backup_code_display_2);
+ codeDisplayText[2] = (TextView) view.findViewById(R.id.backup_code_display_3);
+ codeDisplayText[3] = (TextView) view.findViewById(R.id.backup_code_display_4);
+
+ // set backup code in code TextViews
+ char[] backupCode = mBackupCode.toCharArray();
+ for (int i = 0; i < codeDisplayText.length; i++) {
+ codeDisplayText[i].setText(backupCode, i * 7, 6);
+ }
+
+ // set background to null in TextViews - this will retain padding from EditText style!
+ for (TextView textView : codeDisplayText) {
+ // noinspection deprecation, setBackground(Drawable) is API level >=16
+ textView.setBackgroundDrawable(null);
+ }
+ }
+
+ setupEditTextFocusNext(mCodeEditText);
+ setupEditTextSuccessListener(mCodeEditText);
+
+ mStatusAnimator = (ToolableViewAnimator) view.findViewById(R.id.status_animator);
+ mTitleAnimator = (ToolableViewAnimator) view.findViewById(R.id.title_animator);
+ mCodeFieldsAnimator = (ToolableViewAnimator) view.findViewById(R.id.code_animator);
+
+ View backupInput = view.findViewById(R.id.button_backup_input);
+ backupInput.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ switchState(BackupCodeState.STATE_INPUT, true);
+ }
+ });
+
+ view.findViewById(R.id.button_backup_save).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mShareNotSave = false;
+ startBackup();
+ }
+ });
+
+ view.findViewById(R.id.button_backup_share).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mShareNotSave = true;
+ startBackup();
+ }
+ });
+
+ view.findViewById(R.id.button_backup_back).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FragmentManager fragMan = getFragmentManager();
+ if (fragMan != null) {
+ fragMan.popBackStack();
+ }
+ }
+ });
+
+ return view;
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ if (savedInstanceState != null) {
+ int savedBackStack = savedInstanceState.getInt(ARG_BACK_STACK);
+ if (savedBackStack >= 0) {
+ mBackStackLevel = savedBackStack;
+ // unchecked use, we know that this one is available in onViewCreated
+ getFragmentManager().addOnBackStackChangedListener(this);
+ }
+ BackupCodeState savedState = BackupCodeState.values()[savedInstanceState.getInt(ARG_CURRENT_STATE)];
+ switchState(savedState, false);
+ } else if (mCurrentState == BackupCodeState.STATE_UNINITIALIZED) {
+ switchState(BackupCodeState.STATE_DISPLAY, true);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(ARG_CURRENT_STATE, mCurrentState.ordinal());
+ outState.putInt(ARG_BACK_STACK, mBackStackLevel == null ? -1 : mBackStackLevel);
+ }
+
+ private void setupEditTextSuccessListener(final EditText[] backupCodes) {
+ for (EditText backupCode : backupCodes) {
+
+ backupCode.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (s.length() > 6) {
+ throw new AssertionError("max length of each field is 6!");
+ }
+
+ boolean inInputState = mCurrentState == BackupCodeState.STATE_INPUT
+ || mCurrentState == BackupCodeState.STATE_INPUT_ERROR;
+ boolean partIsComplete = s.length() == 6;
+ if (!inInputState || !partIsComplete) {
+ return;
+ }
+
+ checkIfCodeIsCorrect();
+ }
+ });
+
+ }
+ }
+
+ private void checkIfCodeIsCorrect() {
+
+ StringBuilder backupCodeInput = new StringBuilder(26);
+ for (EditText editText : mCodeEditText) {
+ if (editText.getText().length() < 6) {
+ return;
+ }
+ backupCodeInput.append(editText.getText());
+ backupCodeInput.append('-');
+ }
+ backupCodeInput.deleteCharAt(backupCodeInput.length() - 1);
+
+ // if they don't match, do nothing
+ if (backupCodeInput.toString().equals(mBackupCode)) {
+ switchState(BackupCodeState.STATE_OK, true);
+ return;
+ }
+
+ switchState(BackupCodeState.STATE_INPUT_ERROR, true);
+
+ }
+
+ private static void animateFlashText(
+ final TextView[] textViews, int color1, int color2, boolean staySecondColor) {
+
+ ValueAnimator anim = ValueAnimator.ofObject(new ArgbEvaluator(), color1, color2);
+ anim.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animator) {
+ for (TextView textView : textViews) {
+ textView.setTextColor((Integer) animator.getAnimatedValue());
+ }
+ }
+ });
+ anim.setRepeatMode(ValueAnimator.REVERSE);
+ anim.setRepeatCount(staySecondColor ? 4 : 5);
+ anim.setDuration(180);
+ anim.setInterpolator(new AccelerateInterpolator());
+ anim.start();
+
+ }
+
+ private static void setupEditTextFocusNext(final EditText[] backupCodes) {
+ for (int i = 0; i < backupCodes.length - 1; i++) {
+
+ final int next = i + 1;
+
+ backupCodes[i].addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ boolean inserting = before < count;
+ boolean cursorAtEnd = (start + count) == 6;
+
+ if (inserting && cursorAtEnd) {
+ backupCodes[next].requestFocus();
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ }
+ });
+
+ }
+ }
+
+ private void pushBackStackEntry() {
+ if (mBackStackLevel != null) {
+ return;
+ }
+ FragmentManager fragMan = getFragmentManager();
+ mBackStackLevel = fragMan.getBackStackEntryCount();
+ fragMan.beginTransaction().addToBackStack(BACK_STACK_INPUT).commit();
+ fragMan.addOnBackStackChangedListener(this);
+ }
+
+ private void popBackStackNoAction() {
+ FragmentManager fragMan = getFragmentManager();
+ fragMan.removeOnBackStackChangedListener(this);
+ fragMan.popBackStackImmediate(BACK_STACK_INPUT, FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ mBackStackLevel = null;
+ }
+
+ @Override
+ public void onBackStackChanged() {
+ FragmentManager fragMan = getFragmentManager();
+ if (mBackStackLevel != null && fragMan.getBackStackEntryCount() == mBackStackLevel) {
+ fragMan.removeOnBackStackChangedListener(this);
+ switchState(BackupCodeState.STATE_DISPLAY, true);
+ mBackStackLevel = null;
+ }
+ }
+
+ private void startBackup() {
+
+ FragmentActivity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+
+ String date = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
+ String filename = Constants.FILE_ENCRYPTED_BACKUP_PREFIX + date
+ + (mExportSecret ? Constants.FILE_EXTENSION_ENCRYPTED_BACKUP_SECRET
+ : Constants.FILE_EXTENSION_ENCRYPTED_BACKUP_PUBLIC);
+
+ if (mCachedBackupUri == null) {
+ mCachedBackupUri = TemporaryFileProvider.createFile(activity, filename,
+ Constants.MIME_TYPE_ENCRYPTED_ALTERNATE);
+ cryptoOperation();
+ return;
+ }
+
+ if (mShareNotSave) {
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType(Constants.MIME_TYPE_ENCRYPTED_ALTERNATE);
+ intent.putExtra(Intent.EXTRA_STREAM, mCachedBackupUri);
+ startActivity(intent);
+ } else {
+ saveFile(filename, false);
+ }
+
+ }
+
+ private void saveFile(final String filename, boolean overwrite) {
+ FragmentActivity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+
+ // for kitkat and above, we have the document api
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ FileHelper.saveDocument(this, filename, Constants.MIME_TYPE_ENCRYPTED_ALTERNATE, REQUEST_SAVE);
+ return;
+ }
+
+ File file = new File(Constants.Path.APP_DIR, filename);
+
+ if (!overwrite && file.exists()) {
+ Notify.create(activity, R.string.snack_backup_exists, Style.WARN, new ActionListener() {
+ @Override
+ public void onAction() {
+ saveFile(filename, true);
+ }
+ }, R.string.snack_btn_overwrite).show();
+ return;
+ }
+
+ try {
+ FileHelper.copyUriData(activity, mCachedBackupUri, Uri.fromFile(file));
+ Notify.create(activity, R.string.snack_backup_saved_dir, Style.OK).show();
+ } catch (IOException e) {
+ Notify.create(activity, R.string.snack_backup_error_saving, Style.ERROR).show();
+ }
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode != REQUEST_SAVE) {
+ super.onActivityResult(requestCode, resultCode, data);
+ return;
+ }
+
+ if (resultCode != FragmentActivity.RESULT_OK) {
+ return;
+ }
+
+ FragmentActivity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+ try {
+ Uri outputUri = data.getData();
+ FileHelper.copyUriData(activity, mCachedBackupUri, outputUri);
+ Notify.create(activity, R.string.snack_backup_saved, Style.OK).show();
+ } catch (IOException e) {
+ Notify.create(activity, R.string.snack_backup_error_saving, Style.ERROR).show();
+ }
+ }
+
+ @Nullable
+ @Override
+ public BackupKeyringParcel createOperationInput() {
+ return new BackupKeyringParcel(new Passphrase(mBackupCode), mMasterKeyIds, mExportSecret, mCachedBackupUri);
+ }
+
+ @Override
+ public void onCryptoOperationSuccess(ExportResult result) {
+ startBackup();
+ }
+
+ @Override
+ public void onCryptoOperationError(ExportResult result) {
+ result.createNotify(getActivity()).show();
+ mCachedBackupUri = null;
+ }
+
+ @Override
+ public void onCryptoOperationCancelled() {
+ mCachedBackupUri = null;
+ }
+
+ @NonNull
+ private static String generateRandomCode() {
+
+ Random r = new SecureRandom();
+
+ // simple generation of a 20 character backup code
+ StringBuilder code = new StringBuilder(28);
+ for (int i = 0; i < 24; i++) {
+ if (i == 6 || i == 12 || i == 18) {
+ code.append('-');
+ }
+ code.append((char) ('A' + r.nextInt(26)));
+ }
+
+ return code.toString();
+
+ }
+
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupRestoreFragment.java
index a3ea8ad9a..25601d655 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupRestoreFragment.java
@@ -17,17 +17,13 @@
package org.sufficientlysecure.keychain.ui;
-
-import java.io.File;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
-import java.util.Date;
-import java.util.Locale;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
+import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
@@ -37,41 +33,29 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.util.ExportHelper;
+import org.sufficientlysecure.keychain.ui.util.Notify;
+import org.sufficientlysecure.keychain.util.FileHelper;
-public class BackupFragment extends Fragment {
+public class BackupRestoreFragment extends Fragment {
// This ids for multiple key export.
private ArrayList<Long> mIdsForRepeatAskPassphrase;
// This index for remembering the number of master key.
private int mIndex;
- static final int REQUEST_REPEAT_PASSPHRASE = 1;
- private ExportHelper mExportHelper;
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- // we won't get attached to a non-fragment activity, so the cast should be safe
- mExportHelper = new ExportHelper((FragmentActivity) activity);
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- mExportHelper = null;
- }
+ private static final int REQUEST_REPEAT_PASSPHRASE = 0x00007002;
+ private static final int REQUEST_CODE_INPUT = 0x00007003;
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.backup_fragment, container, false);
+ View view = inflater.inflate(R.layout.backup_restore_fragment, container, false);
View backupAll = view.findViewById(R.id.backup_all);
View backupPublicKeys = view.findViewById(R.id.backup_public_keys);
+ final View restore = view.findViewById(R.id.restore);
backupAll.setOnClickListener(new View.OnClickListener() {
@Override
@@ -87,6 +71,13 @@ public class BackupFragment extends Fragment {
}
});
+ restore.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ restore();
+ }
+ });
+
return view;
}
@@ -101,12 +92,12 @@ public class BackupFragment extends Fragment {
return;
}
- new AsyncTask<ContentResolver,Void,ArrayList<Long>>() {
+ new AsyncTask<ContentResolver, Void, ArrayList<Long>>() {
@Override
protected ArrayList<Long> doInBackground(ContentResolver... resolver) {
ArrayList<Long> askPassphraseIds = new ArrayList<>();
Cursor cursor = resolver[0].query(
- KeyRings.buildUnifiedKeyRingsUri(), new String[] {
+ KeyRings.buildUnifiedKeyRingsUri(), new String[]{
KeyRings.MASTER_KEY_ID,
KeyRings.HAS_SECRET,
}, KeyRings.HAS_SECRET + " != 0", null, null);
@@ -156,7 +147,6 @@ public class BackupFragment extends Fragment {
}
}.execute(activity.getContentResolver());
-
}
private void startPassphraseActivity() {
@@ -173,28 +163,53 @@ public class BackupFragment extends Fragment {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == REQUEST_REPEAT_PASSPHRASE) {
- if (resultCode != Activity.RESULT_OK) {
- return;
+ switch (requestCode) {
+ case REQUEST_REPEAT_PASSPHRASE: {
+ if (resultCode != Activity.RESULT_OK) {
+ return;
+ }
+ if (mIndex < mIdsForRepeatAskPassphrase.size()) {
+ startPassphraseActivity();
+ return;
+ }
+
+ startBackup(true);
+
+ break;
}
- if (mIndex < mIdsForRepeatAskPassphrase.size()) {
- startPassphraseActivity();
- return;
+
+ case REQUEST_CODE_INPUT: {
+ if (resultCode != Activity.RESULT_OK || data == null) {
+ return;
+ }
+
+ Uri uri = data.getData();
+ if (uri == null) {
+ Notify.create(getActivity(), R.string.no_file_selected, Notify.Style.ERROR).show();
+ return;
+ }
+
+ Intent intent = new Intent(getActivity(), DecryptActivity.class);
+ intent.setAction(Intent.ACTION_VIEW);
+ intent.setData(uri);
+ startActivity(intent);
+ break;
}
- startBackup(true);
+ default: {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
}
}
private void startBackup(boolean exportSecret) {
- File filename;
- String date = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
- if (exportSecret) {
- filename = new File(Constants.Path.APP_DIR, "keys_" + date + ".asc");
- } else {
- filename = new File(Constants.Path.APP_DIR, "keys_" + date + ".pub.asc");
- }
- mExportHelper.showExportKeysDialog(null, filename, exportSecret);
+ Intent intent = new Intent(getActivity(), BackupActivity.class);
+ intent.putExtra(BackupActivity.EXTRA_SECRET, exportSecret);
+ startActivity(intent);
+ }
+
+ private void restore() {
+ FileHelper.openDocument(this, null, "*/*", false, REQUEST_CODE_INPUT);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java
index 552fa34c0..85be68505 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java
@@ -33,12 +33,14 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
+import org.sufficientlysecure.keychain.experimental.SentenceConfirm;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.ui.util.ExperimentalWordConfirm;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Log;
+import java.io.IOException;
+
public class CertifyFingerprintFragment extends LoaderFragment implements
LoaderManager.LoaderCallbacks<Cursor> {
@@ -46,24 +48,26 @@ public class CertifyFingerprintFragment extends LoaderFragment implements
static final int REQUEST_CERTIFY = 1;
public static final String ARG_DATA_URI = "uri";
- public static final String ARG_ENABLE_WORD_CONFIRM = "enable_word_confirm";
+ public static final String ARG_ENABLE_PHRASES_CONFIRM = "enable_word_confirm";
+ private TextView mActionYes;
private TextView mFingerprint;
private TextView mIntro;
+ private TextView mHeader;
private static final int LOADER_ID_UNIFIED = 0;
private Uri mDataUri;
- private boolean mEnableWordConfirm;
+ private boolean mEnablePhrasesConfirm;
/**
* Creates new instance of this fragment
*/
- public static CertifyFingerprintFragment newInstance(Uri dataUri, boolean enableWordConfirm) {
+ public static CertifyFingerprintFragment newInstance(Uri dataUri, boolean enablePhrasesConfirm) {
CertifyFingerprintFragment frag = new CertifyFingerprintFragment();
Bundle args = new Bundle();
args.putParcelable(ARG_DATA_URI, dataUri);
- args.putBoolean(ARG_ENABLE_WORD_CONFIRM, enableWordConfirm);
+ args.putBoolean(ARG_ENABLE_PHRASES_CONFIRM, enablePhrasesConfirm);
frag.setArguments(args);
@@ -75,11 +79,12 @@ public class CertifyFingerprintFragment extends LoaderFragment implements
View root = super.onCreateView(inflater, superContainer, savedInstanceState);
View view = inflater.inflate(R.layout.certify_fingerprint_fragment, getContainer());
- View actionNo = view.findViewById(R.id.certify_fingerprint_button_no);
- View actionYes = view.findViewById(R.id.certify_fingerprint_button_yes);
+ TextView actionNo = (TextView) view.findViewById(R.id.certify_fingerprint_button_no);
+ mActionYes = (TextView) view.findViewById(R.id.certify_fingerprint_button_yes);
mFingerprint = (TextView) view.findViewById(R.id.certify_fingerprint_fingerprint);
mIntro = (TextView) view.findViewById(R.id.certify_fingerprint_intro);
+ mHeader = (TextView) view.findViewById(R.id.certify_fingerprint_fingerprint_header);
actionNo.setOnClickListener(new View.OnClickListener() {
@Override
@@ -87,7 +92,7 @@ public class CertifyFingerprintFragment extends LoaderFragment implements
getActivity().finish();
}
});
- actionYes.setOnClickListener(new View.OnClickListener() {
+ mActionYes.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
certify(mDataUri);
@@ -107,10 +112,12 @@ public class CertifyFingerprintFragment extends LoaderFragment implements
getActivity().finish();
return;
}
- mEnableWordConfirm = getArguments().getBoolean(ARG_ENABLE_WORD_CONFIRM);
+ mEnablePhrasesConfirm = getArguments().getBoolean(ARG_ENABLE_PHRASES_CONFIRM);
- if (mEnableWordConfirm) {
- mIntro.setText(R.string.certify_fingerprint_text_words);
+ if (mEnablePhrasesConfirm) {
+ mIntro.setText(R.string.certify_fingerprint_text_phrases);
+ mHeader.setText(R.string.section_phrases);
+ mActionYes.setText(R.string.btn_match_phrases);
}
loadData(dataUri);
@@ -160,7 +167,7 @@ public class CertifyFingerprintFragment extends LoaderFragment implements
if (data.moveToFirst()) {
byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT);
- if (mEnableWordConfirm) {
+ if (mEnablePhrasesConfirm) {
displayWordConfirm(fingerprintBlob);
} else {
displayHexConfirm(fingerprintBlob);
@@ -180,9 +187,17 @@ public class CertifyFingerprintFragment extends LoaderFragment implements
}
private void displayWordConfirm(byte[] fingerprintBlob) {
- String fingerprint = ExperimentalWordConfirm.getWords(getActivity(), fingerprintBlob);
+// String fingerprint = ExperimentalWordConfirm.getWords(getActivity(), fingerprintBlob);
+
+ String fingerprint;
+ try {
+ fingerprint = new SentenceConfirm(getActivity()).fromBytes(fingerprintBlob, 20);
+ } catch (IOException e) {
+ fingerprint = "-";
+ Log.e(Constants.TAG, "Problem when creating sentence!", e);
+ }
- mFingerprint.setTextSize(24);
+ mFingerprint.setTextSize(18);
mFingerprint.setTypeface(Typeface.DEFAULT, Typeface.BOLD);
mFingerprint.setText(fingerprint);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java
index 579a001cb..a4163d7f9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java
@@ -30,7 +30,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
-import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.Preferences;
@@ -114,19 +113,15 @@ public class CreateKeyActivity extends BaseNfcActivity {
byte[] nfcAid = intent.getByteArrayExtra(EXTRA_NFC_AID);
if (containsKeys(nfcFingerprints)) {
- Fragment frag = CreateYubiKeyImportFragment.newInstance(
+ Fragment frag = CreateYubiKeyImportResetFragment.newInstance(
nfcFingerprints, nfcAid, nfcUserId);
loadFragment(frag, FragAction.START);
setTitle(R.string.title_import_keys);
} else {
-// Fragment frag = CreateYubiKeyBlankFragment.newInstance();
-// loadFragment(frag, FragAction.START);
-// setTitle(R.string.title_manage_my_keys);
- Notify.create(this,
- "YubiKey key creation is currently not supported. Please follow our FAQ.",
- Notify.Style.ERROR
- ).show();
+ Fragment frag = CreateYubiKeyBlankFragment.newInstance();
+ loadFragment(frag, FragAction.START);
+ setTitle(R.string.title_manage_my_keys);
}
// done
@@ -160,7 +155,7 @@ public class CreateKeyActivity extends BaseNfcActivity {
}
@Override
- protected void onNfcPostExecute() throws IOException {
+ protected void onNfcPostExecute() {
if (mCurrentFragment instanceof NfcListenerFragment) {
((NfcListenerFragment) mCurrentFragment).onNfcPostExecute();
return;
@@ -181,30 +176,28 @@ public class CreateKeyActivity extends BaseNfcActivity {
finish();
} catch (PgpKeyNotFoundException e) {
- Fragment frag = CreateYubiKeyImportFragment.newInstance(
+ Fragment frag = CreateYubiKeyImportResetFragment.newInstance(
mScannedFingerprints, mNfcAid, mNfcUserId);
loadFragment(frag, FragAction.TO_RIGHT);
}
} else {
-// Fragment frag = CreateYubiKeyBlankFragment.newInstance();
-// loadFragment(frag, FragAction.TO_RIGHT);
- Notify.create(this,
- "YubiKey key creation is currently not supported. Please follow our FAQ.",
- Notify.Style.ERROR
- ).show();
+ Fragment frag = CreateYubiKeyBlankFragment.newInstance();
+ loadFragment(frag, FragAction.TO_RIGHT);
}
}
private boolean containsKeys(byte[] scannedFingerprints) {
+ if (scannedFingerprints == null) {
+ return false;
+ }
+
// If all fingerprint bytes are 0, the card contains no keys.
- boolean cardContainsKeys = false;
for (byte b : scannedFingerprints) {
if (b != 0) {
- cardContainsKeys = true;
- break;
+ return true;
}
}
- return cardContainsKeys;
+ return false;
}
@Override
@@ -264,7 +257,7 @@ public class CreateKeyActivity extends BaseNfcActivity {
interface NfcListenerFragment {
void doNfcInBackground() throws IOException;
- void onNfcPostExecute() throws IOException;
+ void onNfcPostExecute();
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
index 739eb3e35..b79e4454d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java
@@ -37,17 +37,17 @@ import org.spongycastle.bcpg.sig.KeyFlags;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
-import org.sufficientlysecure.keychain.operations.results.ExportResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
+import org.sufficientlysecure.keychain.operations.results.UploadResult;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.ExportKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
+import org.sufficientlysecure.keychain.service.UploadKeyringParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
@@ -69,7 +69,7 @@ public class CreateKeyFinalFragment extends Fragment {
SaveKeyringParcel mSaveKeyringParcel;
- private CryptoOperationHelper<ExportKeyringParcel, ExportResult> mUploadOpHelper;
+ private CryptoOperationHelper<UploadKeyringParcel, UploadResult> mUploadOpHelper;
private CryptoOperationHelper<SaveKeyringParcel, EditKeyResult> mCreateOpHelper;
private CryptoOperationHelper<SaveKeyringParcel, EditKeyResult> mMoveToCardOpHelper;
@@ -407,20 +407,20 @@ public class CreateKeyFinalFragment extends Fragment {
}
// set data uri as path to keyring
- final Uri blobUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(saveKeyResult.mMasterKeyId);
+ final long masterKeyId = saveKeyResult.mMasterKeyId;
// upload to favorite keyserver
final String keyserver = Preferences.getPreferences(activity).getPreferredKeyserver();
- CryptoOperationHelper.Callback<ExportKeyringParcel, ExportResult> callback
- = new CryptoOperationHelper.Callback<ExportKeyringParcel, ExportResult>() {
+ CryptoOperationHelper.Callback<UploadKeyringParcel, UploadResult> callback
+ = new CryptoOperationHelper.Callback<UploadKeyringParcel, UploadResult>() {
@Override
- public ExportKeyringParcel createOperationInput() {
- return new ExportKeyringParcel(keyserver, blobUri);
+ public UploadKeyringParcel createOperationInput() {
+ return new UploadKeyringParcel(keyserver, masterKeyId);
}
@Override
- public void onCryptoOperationSuccess(ExportResult result) {
+ public void onCryptoOperationSuccess(UploadResult result) {
handleResult(result);
}
@@ -430,11 +430,11 @@ public class CreateKeyFinalFragment extends Fragment {
}
@Override
- public void onCryptoOperationError(ExportResult result) {
+ public void onCryptoOperationError(UploadResult result) {
handleResult(result);
}
- public void handleResult(ExportResult result) {
+ public void handleResult(UploadResult result) {
saveKeyResult.getLog().add(result, 0);
finishWithResult(saveKeyResult);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportResetFragment.java
index d88e6b9f9..0a2d52617 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyImportResetFragment.java
@@ -25,11 +25,13 @@ import java.util.ArrayList;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
+import android.os.Parcelable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.ViewGroup;
+import android.widget.CompoundButton;
+import android.widget.RadioButton;
import android.widget.TextView;
import org.spongycastle.util.encoders.Hex;
@@ -38,6 +40,8 @@ import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.NfcListenerFragment;
import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
@@ -45,11 +49,13 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Preferences;
-public class CreateYubiKeyImportFragment
+public class CreateYubiKeyImportResetFragment
extends QueueingCryptoOperationFragment<ImportKeyringParcel, ImportKeyResult>
implements NfcListenerFragment {
- private static final String ARG_FINGERPRINT = "fingerprint";
+ private static final int REQUEST_CODE_RESET = 0x00005001;
+
+ private static final String ARG_FINGERPRINTS = "fingerprint";
public static final String ARG_AID = "aid";
public static final String ARG_USER_ID = "user_ids";
@@ -62,6 +68,10 @@ public class CreateYubiKeyImportFragment
private ImportKeysListFragment mListFragment;
private TextView vSerNo;
private TextView vUserId;
+ private TextView mNextButton;
+ private RadioButton mRadioImport;
+ private RadioButton mRadioReset;
+ private View mResetWarning;
// for CryptoOperationFragment key import
private String mKeyserver;
@@ -69,10 +79,10 @@ public class CreateYubiKeyImportFragment
public static Fragment newInstance(byte[] scannedFingerprints, byte[] nfcAid, String userId) {
- CreateYubiKeyImportFragment frag = new CreateYubiKeyImportFragment();
+ CreateYubiKeyImportResetFragment frag = new CreateYubiKeyImportResetFragment();
Bundle args = new Bundle();
- args.putByteArray(ARG_FINGERPRINT, scannedFingerprints);
+ args.putByteArray(ARG_FINGERPRINTS, scannedFingerprints);
args.putByteArray(ARG_AID, nfcAid);
args.putString(ARG_USER_ID, userId);
frag.setArguments(args);
@@ -86,7 +96,7 @@ public class CreateYubiKeyImportFragment
Bundle args = savedInstanceState != null ? savedInstanceState : getArguments();
- mNfcFingerprints = args.getByteArray(ARG_FINGERPRINT);
+ mNfcFingerprints = args.getByteArray(ARG_FINGERPRINTS);
mNfcAid = args.getByteArray(ARG_AID);
mNfcUserId = args.getString(ARG_USER_ID);
@@ -98,49 +108,78 @@ public class CreateYubiKeyImportFragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.create_yubi_key_import_fragment, container, false);
+ View view = inflater.inflate(R.layout.create_yubi_key_import_reset_fragment, container, false);
vSerNo = (TextView) view.findViewById(R.id.yubikey_serno);
vUserId = (TextView) view.findViewById(R.id.yubikey_userid);
+ mNextButton = (TextView) view.findViewById(R.id.create_key_next_button);
+ mRadioImport = (RadioButton) view.findViewById(R.id.yubikey_decision_import);
+ mRadioReset = (RadioButton) view.findViewById(R.id.yubikey_decision_reset);
+ mResetWarning = view.findViewById(R.id.yubikey_import_reset_warning);
- {
- View mBackButton = view.findViewById(R.id.create_key_back_button);
- mBackButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (getFragmentManager().getBackStackEntryCount() == 0) {
- getActivity().setResult(Activity.RESULT_CANCELED);
- getActivity().finish();
- } else {
- mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
- }
+ View mBackButton = view.findViewById(R.id.create_key_back_button);
+ mBackButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (getFragmentManager().getBackStackEntryCount() == 0) {
+ getActivity().setResult(Activity.RESULT_CANCELED);
+ getActivity().finish();
+ } else {
+ mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
}
- });
+ }
+ });
- View mNextButton = view.findViewById(R.id.create_key_next_button);
- mNextButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
+ mNextButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mRadioReset.isChecked()) {
+ resetCard();
+ } else {
importKey();
}
- });
- }
+ }
+ });
mListFragment = ImportKeysListFragment.newInstance(null, null,
"0x" + mNfcFingerprint, true, null);
- view.findViewById(R.id.button_search).setOnClickListener(new OnClickListener() {
+ mRadioImport.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
- public void onClick(View v) {
- refreshSearch();
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (isChecked) {
+ mNextButton.setText(R.string.btn_import);
+ mNextButton.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_key_plus_grey600_24dp, 0);
+ mNextButton.setVisibility(View.VISIBLE);
+ mResetWarning.setVisibility(View.GONE);
+
+ getFragmentManager().beginTransaction()
+ .replace(R.id.yubikey_import_fragment, mListFragment, "yubikey_import")
+ .commit();
+
+ getFragmentManager().executePendingTransactions();
+ refreshSearch();
+ }
+ }
+ });
+ mRadioReset.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (isChecked) {
+ mNextButton.setText(R.string.btn_reset);
+ mNextButton.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_close_grey_24dp, 0);
+ mNextButton.setVisibility(View.VISIBLE);
+ mResetWarning.setVisibility(View.VISIBLE);
+
+ getFragmentManager().beginTransaction()
+ .remove(mListFragment)
+ .commit();
+ }
}
});
setData();
- getFragmentManager().beginTransaction()
- .replace(R.id.yubikey_import_fragment, mListFragment, "yubikey_import")
- .commit();
return view;
}
@@ -149,7 +188,7 @@ public class CreateYubiKeyImportFragment
public void onSaveInstanceState(Bundle args) {
super.onSaveInstanceState(args);
- args.putByteArray(ARG_FINGERPRINT, mNfcFingerprints);
+ args.putByteArray(ARG_FINGERPRINTS, mNfcFingerprints);
args.putByteArray(ARG_AID, mNfcAid);
args.putString(ARG_USER_ID, mNfcUserId);
}
@@ -195,6 +234,25 @@ public class CreateYubiKeyImportFragment
}
+ public void resetCard() {
+ Intent intent = new Intent(getActivity(), NfcOperationActivity.class);
+ intent.putExtra(NfcOperationActivity.EXTRA_SERVICE_INTENT, (Parcelable[]) null);
+ RequiredInputParcel resetP = RequiredInputParcel.createNfcReset();
+ intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, resetP);
+ intent.putExtra(NfcOperationActivity.EXTRA_CRYPTO_INPUT, new CryptoInputParcel());
+ startActivityForResult(intent, REQUEST_CODE_RESET);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_CODE_RESET && resultCode == Activity.RESULT_OK) {
+ mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
+ return;
+ }
+
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
@Override
public void doNfcInBackground() throws IOException {
@@ -208,11 +266,10 @@ public class CreateYubiKeyImportFragment
}
@Override
- public void onNfcPostExecute() throws IOException {
+ public void onNfcPostExecute() {
setData();
- refreshSearch();
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinFragment.java
index a793b31f2..128383d6d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinFragment.java
@@ -18,13 +18,15 @@
package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
+import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
-import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
@@ -32,16 +34,34 @@ import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.HashSet;
public class CreateYubiKeyPinFragment extends Fragment {
// view
CreateKeyActivity mCreateKeyActivity;
- TextView mPin;
+ EditText mPin;
+ EditText mPinRepeat;
TextView mAdminPin;
View mBackButton;
View mNextButton;
+ private static HashSet<String> sPinBlacklist = new HashSet<>(Arrays.asList(
+ "000000",
+ "111111",
+ "222222",
+ "333333",
+ "444444",
+ "555555",
+ "666666",
+ "777777",
+ "888888",
+ "999999",
+ "123456",
+ "XXXXXX"
+ ));
+
/**
* Creates new instance of this fragment
*/
@@ -54,50 +74,71 @@ public class CreateYubiKeyPinFragment extends Fragment {
return frag;
}
+ /**
+ * Checks if text of given EditText is not empty. If it is empty an error is
+ * set and the EditText gets the focus.
+ *
+ * @return true if EditText is not empty
+ */
+ private static boolean isEditTextNotEmpty(Context context, EditText editText) {
+ boolean output = true;
+ if (editText.getText().length() == 0) {
+ editText.setError(context.getString(R.string.create_key_empty));
+ editText.requestFocus();
+ output = false;
+ } else {
+ editText.setError(null);
+ }
+
+ return output;
+ }
+
+ private static boolean areEditTextsEqual(EditText editText1, EditText editText2) {
+ Passphrase p1 = new Passphrase(editText1);
+ Passphrase p2 = new Passphrase(editText2);
+ return (p1.equals(p2));
+ }
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.create_yubi_key_pin_fragment, container, false);
- mPin = (TextView) view.findViewById(R.id.create_yubi_key_pin);
+ mPin = (EditText) view.findViewById(R.id.create_yubi_key_pin);
+ mPinRepeat = (EditText) view.findViewById(R.id.create_yubi_key_pin_repeat);
mAdminPin = (TextView) view.findViewById(R.id.create_yubi_key_admin_pin);
mBackButton = view.findViewById(R.id.create_key_back_button);
mNextButton = view.findViewById(R.id.create_key_next_button);
if (mCreateKeyActivity.mYubiKeyPin == null) {
- new AsyncTask<Void, Void, Pair<Passphrase, Passphrase>>() {
+ new AsyncTask<Void, Void, Passphrase>() {
@Override
- protected Pair<Passphrase, Passphrase> doInBackground(Void... unused) {
+ protected Passphrase doInBackground(Void... unused) {
SecureRandom secureRandom = new SecureRandom();
- // min = 6, we choose 6
- String pin = "" + secureRandom.nextInt(9)
+ // min = 8, we choose 8
+ String adminPin = "" + secureRandom.nextInt(9)
+ secureRandom.nextInt(9)
+ secureRandom.nextInt(9)
+ secureRandom.nextInt(9)
+ secureRandom.nextInt(9)
- + secureRandom.nextInt(9);
- // min = 8, we choose 10, but 6 are equals the PIN
- String adminPin = pin + secureRandom.nextInt(9)
+ secureRandom.nextInt(9)
+ secureRandom.nextInt(9)
+ secureRandom.nextInt(9);
- return new Pair<>(new Passphrase(pin), new Passphrase(adminPin));
+ return new Passphrase(adminPin);
}
@Override
- protected void onPostExecute(Pair<Passphrase, Passphrase> pair) {
- mCreateKeyActivity.mYubiKeyPin = pair.first;
- mCreateKeyActivity.mYubiKeyAdminPin = pair.second;
+ protected void onPostExecute(Passphrase adminPin) {
+ mCreateKeyActivity.mYubiKeyAdminPin = adminPin;
- mPin.setText(mCreateKeyActivity.mYubiKeyPin.toStringUnsafe());
mAdminPin.setText(mCreateKeyActivity.mYubiKeyAdminPin.toStringUnsafe());
}
}.execute();
} else {
- mPin.setText(mCreateKeyActivity.mYubiKeyPin.toStringUnsafe());
mAdminPin.setText(mCreateKeyActivity.mYubiKeyAdminPin.toStringUnsafe());
}
+ mPin.requestFocus();
mBackButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -111,7 +152,6 @@ public class CreateYubiKeyPinFragment extends Fragment {
}
});
-
return view;
}
@@ -121,14 +161,53 @@ public class CreateYubiKeyPinFragment extends Fragment {
mCreateKeyActivity = (CreateKeyActivity) getActivity();
}
+ private void back() {
+ hideKeyboard();
+ mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
+ }
private void nextClicked() {
- CreateYubiKeyPinRepeatFragment frag = CreateYubiKeyPinRepeatFragment.newInstance();
- mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
+ if (isEditTextNotEmpty(getActivity(), mPin)) {
+
+ if (!areEditTextsEqual(mPin, mPinRepeat)) {
+ mPinRepeat.setError(getString(R.string.create_key_passphrases_not_equal));
+ mPinRepeat.requestFocus();
+ return;
+ }
+
+ if (mPin.getText().toString().length() < 6) {
+ mPin.setError(getString(R.string.create_key_yubi_key_pin_too_short));
+ mPin.requestFocus();
+ return;
+ }
+
+ if (sPinBlacklist.contains(mPin.getText().toString())) {
+ mPin.setError(getString(R.string.create_key_yubi_key_pin_insecure));
+ mPin.requestFocus();
+ return;
+ }
+
+ mCreateKeyActivity.mYubiKeyPin = new Passphrase(mPin.getText().toString());
+
+ CreateKeyFinalFragment frag = CreateKeyFinalFragment.newInstance();
+ hideKeyboard();
+ mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
+ }
}
- private void back() {
- mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
+ private void hideKeyboard() {
+ if (getActivity() == null) {
+ return;
+ }
+ InputMethodManager inputManager = (InputMethodManager) getActivity()
+ .getSystemService(Context.INPUT_METHOD_SERVICE);
+
+ // check if no view has focus
+ View v = getActivity().getCurrentFocus();
+ if (v == null)
+ return;
+
+ inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinRepeatFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinRepeatFragment.java
deleted file mode 100644
index 2e752e609..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateYubiKeyPinRepeatFragment.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.ui;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.EditText;
-
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
-
-public class CreateYubiKeyPinRepeatFragment extends Fragment {
-
- // view
- CreateKeyActivity mCreateKeyActivity;
- EditText mPin;
- EditText mAdminPin;
- View mBackButton;
- View mNextButton;
-
- /**
- * Creates new instance of this fragment
- */
- public static CreateYubiKeyPinRepeatFragment newInstance() {
- CreateYubiKeyPinRepeatFragment frag = new CreateYubiKeyPinRepeatFragment();
-
- Bundle args = new Bundle();
- frag.setArguments(args);
-
- return frag;
- }
-
- /**
- * Checks if text of given EditText is not empty. If it is empty an error is
- * set and the EditText gets the focus.
- *
- * @param context
- * @param editText
- * @return true if EditText is not empty
- */
- private static boolean isEditTextNotEmpty(Context context, EditText editText) {
- boolean output = true;
- if (editText.getText().length() == 0) {
- editText.setError(context.getString(R.string.create_key_empty));
- editText.requestFocus();
- output = false;
- } else {
- editText.setError(null);
- }
-
- return output;
- }
-
- private static boolean checkPin(Context context, EditText editText1, String pin) {
- boolean output = editText1.getText().toString().equals(pin);
-
- if (!output) {
- editText1.setError(context.getString(R.string.create_key_yubi_key_pin_not_correct));
- editText1.requestFocus();
- } else {
- editText1.setError(null);
- }
-
- return output;
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.create_yubi_key_pin_repeat_fragment, container, false);
-
- mPin = (EditText) view.findViewById(R.id.create_yubi_key_pin_repeat);
- mAdminPin = (EditText) view.findViewById(R.id.create_yubi_key_admin_pin_repeat);
- mBackButton = view.findViewById(R.id.create_key_back_button);
- mNextButton = view.findViewById(R.id.create_key_next_button);
-
- mPin.requestFocus();
- mBackButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- back();
- }
- });
- mNextButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- nextClicked();
- }
- });
-
- return view;
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- mCreateKeyActivity = (CreateKeyActivity) getActivity();
- }
-
- private void back() {
- hideKeyboard();
- mCreateKeyActivity.loadFragment(null, FragAction.TO_LEFT);
- }
-
- private void nextClicked() {
- if (isEditTextNotEmpty(getActivity(), mPin)
- && checkPin(getActivity(), mPin, mCreateKeyActivity.mYubiKeyPin.toStringUnsafe())
- && isEditTextNotEmpty(getActivity(), mAdminPin)
- && checkPin(getActivity(), mAdminPin, mCreateKeyActivity.mYubiKeyAdminPin.toStringUnsafe())) {
-
- CreateKeyFinalFragment frag = CreateKeyFinalFragment.newInstance();
- hideKeyboard();
- mCreateKeyActivity.loadFragment(frag, FragAction.TO_RIGHT);
- }
- }
-
- private void hideKeyboard() {
- if (getActivity() == null) {
- return;
- }
- InputMethodManager inputManager = (InputMethodManager) getActivity()
- .getSystemService(Context.INPUT_METHOD_SERVICE);
-
- // check if no view has focus
- View v = getActivity().getCurrentFocus();
- if (v == null)
- return;
-
- inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
- }
-
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
index 4e9a6f17d..cf7a0b1d7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
@@ -37,7 +37,7 @@ import android.widget.Toast;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.intents.OpenKeychainIntents;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
-import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
+import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
@@ -193,14 +193,14 @@ public class DecryptActivity extends BaseActivity {
@Nullable
public Uri readToTempFile(String text) throws IOException {
- Uri tempFile = TemporaryStorageProvider.createFile(this);
+ Uri tempFile = TemporaryFileProvider.createFile(this);
OutputStream outStream = getContentResolver().openOutputStream(tempFile);
if (outStream == null) {
return null;
}
// clean up ascii armored message, fixing newlines and stuff
- String cleanedText = PgpHelper.getPgpContent(text);
+ String cleanedText = PgpHelper.getPgpMessageContent(text);
if (cleanedText == null) {
return null;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java
index dcba595e9..8adaa0670 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java
@@ -22,13 +22,17 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
+import android.Manifest;
+import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ClipDescription;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LabeledIntent;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.Point;
@@ -36,8 +40,12 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.v4.content.ContextCompat;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
@@ -65,10 +73,14 @@ import org.openintents.openpgp.OpenPgpSignatureResult;
import org.sufficientlysecure.keychain.BuildConfig;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
+import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.InputDataResult;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.service.InputDataParcel;
+import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment;
// this import NEEDS to be above the ViewModel AND SubViewHolder one, or it won't compile! (as of 16.09.15)
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.StatusHolder;
@@ -82,8 +94,25 @@ import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.FileHelper;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ParcelableHashMap;
+import org.sufficientlysecure.keychain.util.Preferences;
+/** Displays a list of decrypted inputs.
+ *
+ * This class has a complex control flow to manage its input URIs. Each URI
+ * which is in mInputUris is also in exactly one of mPendingInputUris,
+ * mCancelledInputUris, mCurrentInputUri, or a key in mInputDataResults.
+ *
+ * Processing of URIs happens using a looping approach:
+ * - There is always exactly one method running which works on mCurrentInputUri
+ * - Processing starts in cryptoOperation(), which pops a new mCurrentInputUri
+ * from the list of mPendingInputUris.
+ * - Once a mCurrentInputUri is finished processing, it should be set to null and
+ * control handed back to cryptoOperation()
+ * - Control flow can move through asynchronous calls, and resume in callbacks
+ * like onActivityResult() or onPermissionRequestResult().
+ *
+ */
public class DecryptListFragment
extends QueueingCryptoOperationFragment<InputDataParcel,InputDataResult>
implements OnMenuItemClickListener {
@@ -95,7 +124,7 @@ public class DecryptListFragment
public static final String ARG_CAN_DELETE = "can_delete";
private static final int REQUEST_CODE_OUTPUT = 0x00007007;
- public static final String ARG_CURRENT_URI = "current_uri";
+ private static final int REQUEST_PERMISSION_READ_EXTERNAL_STORAGE = 12;
private ArrayList<Uri> mInputUris;
private HashMap<Uri, InputDataResult> mInputDataResults;
@@ -111,7 +140,7 @@ public class DecryptListFragment
/**
* Creates new instance of this fragment
*/
- public static DecryptListFragment newInstance(ArrayList<Uri> uris, boolean canDelete) {
+ public static DecryptListFragment newInstance(@NonNull ArrayList<Uri> uris, boolean canDelete) {
DecryptListFragment frag = new DecryptListFragment();
Bundle args = new Bundle();
@@ -168,9 +197,12 @@ public class DecryptListFragment
outState.putParcelable(ARG_RESULTS, new ParcelableHashMap<>(results));
outState.putParcelable(ARG_OUTPUT_URIS, new ParcelableHashMap<>(mInputDataResults));
outState.putParcelableArrayList(ARG_CANCELLED_URIS, mCancelledInputUris);
- outState.putParcelable(ARG_CURRENT_URI, mCurrentInputUri);
outState.putBoolean(ARG_CAN_DELETE, mCanDelete);
+ // this does not save mCurrentInputUri - if anything is being
+ // processed at fragment recreation time, the operation in
+ // progress will be lost!
+
}
@Override
@@ -182,20 +214,21 @@ public class DecryptListFragment
ArrayList<Uri> inputUris = getArguments().getParcelableArrayList(ARG_INPUT_URIS);
ArrayList<Uri> cancelledUris = args.getParcelableArrayList(ARG_CANCELLED_URIS);
ParcelableHashMap<Uri,InputDataResult> results = args.getParcelable(ARG_RESULTS);
- Uri currentInputUri = args.getParcelable(ARG_CURRENT_URI);
mCanDelete = args.getBoolean(ARG_CAN_DELETE, false);
- displayInputUris(inputUris, currentInputUri, cancelledUris,
+ displayInputUris(inputUris, cancelledUris,
results != null ? results.getMap() : null
);
}
- private void displayInputUris(ArrayList<Uri> inputUris, Uri currentInputUri,
- ArrayList<Uri> cancelledUris, HashMap<Uri,InputDataResult> results) {
+ private void displayInputUris(
+ ArrayList<Uri> inputUris,
+ ArrayList<Uri> cancelledUris,
+ HashMap<Uri,InputDataResult> results) {
mInputUris = inputUris;
- mCurrentInputUri = currentInputUri;
+ mCurrentInputUri = null;
mInputDataResults = results != null ? results : new HashMap<Uri,InputDataResult>(inputUris.size());
mCancelledInputUris = cancelledUris != null ? cancelledUris : new ArrayList<Uri>();
@@ -204,30 +237,23 @@ public class DecryptListFragment
for (final Uri uri : inputUris) {
mAdapter.add(uri);
- if (uri.equals(mCurrentInputUri)) {
+ boolean uriIsCancelled = mCancelledInputUris.contains(uri);
+ if (uriIsCancelled) {
+ mAdapter.setCancelled(uri, true);
continue;
}
- if (mCancelledInputUris.contains(uri)) {
- mAdapter.setCancelled(uri, new OnClickListener() {
- @Override
- public void onClick(View v) {
- retryUri(uri);
- }
- });
+ boolean uriHasResult = results != null && results.containsKey(uri);
+ if (uriHasResult) {
+ processResult(uri);
continue;
}
- if (results != null && results.containsKey(uri)) {
- processResult(uri);
- } else {
- mPendingInputUris.add(uri);
- }
+ mPendingInputUris.add(uri);
}
- if (mCurrentInputUri == null) {
- cryptoOperation();
- }
+ // check if there are any pending input uris
+ cryptoOperation();
}
@Override
@@ -249,6 +275,7 @@ public class DecryptListFragment
}
}
+ @TargetApi(VERSION_CODES.KITKAT)
private void saveFileDialog(InputDataResult result, int index) {
Activity activity = getActivity();
@@ -257,17 +284,16 @@ public class DecryptListFragment
}
OpenPgpMetadata metadata = result.mMetadata.get(index);
- Uri saveUri = Uri.fromFile(activity.getExternalFilesDir(metadata.getMimeType()));
mCurrentSaveFileUri = result.getOutputUris().get(index);
String filename = metadata.getFilename();
- if (filename == null) {
+ if (TextUtils.isEmpty(filename)) {
String ext = MimeTypeMap.getSingleton().getExtensionFromMimeType(metadata.getMimeType());
filename = "decrypted" + (ext != null ? "."+ext : "");
}
- FileHelper.saveDocument(this, filename, saveUri, metadata.getMimeType(),
- R.string.title_decrypt_to_file, R.string.specify_file_to_decrypt_to, REQUEST_CODE_OUTPUT);
+ // requires >=kitkat
+ FileHelper.saveDocument(this, filename, metadata.getMimeType(), REQUEST_CODE_OUTPUT);
}
private void saveFile(Uri saveUri) {
@@ -320,6 +346,29 @@ public class DecryptListFragment
Uri uri = mCurrentInputUri;
mCurrentInputUri = null;
+ Activity activity = getActivity();
+
+ boolean isSingleInput = mInputDataResults.isEmpty() && mPendingInputUris.isEmpty();
+ if (isSingleInput) {
+
+ // there is always at least one mMetadata object, so we know this is >= 1 already
+ boolean isSingleMetadata = result.mMetadata.size() == 1;
+ OpenPgpMetadata metadata = result.mMetadata.get(0);
+ boolean isText = "text/plain".equals(metadata.getMimeType());
+ boolean isOverSized = metadata.getOriginalSize() > Constants.TEXT_LENGTH_LIMIT;
+
+ if (isSingleMetadata && isText && !isOverSized) {
+ Intent displayTextIntent = new Intent(activity, DisplayTextActivity.class)
+ .setDataAndType(result.mOutputUris.get(0), "text/plain")
+ .putExtra(DisplayTextActivity.EXTRA_RESULT, result.mDecryptVerifyResult)
+ .putExtra(DisplayTextActivity.EXTRA_METADATA, metadata);
+ activity.startActivity(displayTextIntent);
+ activity.finish();
+ return;
+ }
+
+ }
+
mInputDataResults.put(uri, result);
processResult(uri);
@@ -334,12 +383,7 @@ public class DecryptListFragment
mCurrentInputUri = null;
mCancelledInputUris.add(uri);
- mAdapter.setCancelled(uri, new OnClickListener() {
- @Override
- public void onClick(View v) {
- retryUri(uri);
- }
- });
+ mAdapter.setCancelled(uri, true);
cryptoOperation();
@@ -375,11 +419,20 @@ public class DecryptListFragment
if (ClipDescription.compareMimeTypes(type, "text/plain")) {
// noinspection deprecation, this should be called from Context, but not available in minSdk
icon = getResources().getDrawable(R.drawable.ic_chat_black_24dp);
+ } else if (ClipDescription.compareMimeTypes(type, "application/octet-stream")) {
+ // icons for this are just confusing
+ // noinspection deprecation, this should be called from Context, but not available in minSdk
+ icon = getResources().getDrawable(R.drawable.ic_doc_generic_am);
+ } else if (ClipDescription.compareMimeTypes(type, Constants.MIME_TYPE_KEYS)) {
+ // noinspection deprecation, this should be called from Context, but not available in minSdk
+ icon = getResources().getDrawable(R.drawable.ic_key_plus_grey600_24dp);
} else if (ClipDescription.compareMimeTypes(type, "image/*")) {
- int px = FormattingUtils.dpToPx(context, 48);
+ int px = FormattingUtils.dpToPx(context, 32);
Bitmap bitmap = FileHelper.getThumbnail(context, outputUri, new Point(px, px));
icon = new BitmapDrawable(context.getResources(), bitmap);
- } else {
+ }
+
+ if (icon == null) {
final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(outputUri, type);
@@ -420,11 +473,12 @@ public class DecryptListFragment
// un-cancel this one
mCancelledInputUris.remove(uri);
+ mInputDataResults.remove(uri);
mPendingInputUris.add(uri);
- mAdapter.setCancelled(uri, null);
+ mAdapter.resetItemData(uri);
+ // check if there are any pending input uris
cryptoOperation();
-
}
public void displayBottomSheet(final InputDataResult result, final int index) {
@@ -445,6 +499,7 @@ public class DecryptListFragment
displayWithViewIntent(result, index, true, true);
break;
case R.id.decrypt_save:
+ // only inside the menu xml for Android >= 4.4
saveFileDialog(result, index);
break;
}
@@ -525,6 +580,11 @@ public class DecryptListFragment
} else {
intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(outputUri, metadata.getMimeType());
+
+ if (!forceChooser && Constants.MIME_TYPE_KEYS.equals(metadata.getMimeType())) {
+ // bind Intent to this OpenKeychain, don't allow other apps to intercept here!
+ intent.setPackage(getActivity().getPackageName());
+ }
}
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
@@ -539,6 +599,11 @@ public class DecryptListFragment
@Override
public InputDataParcel createOperationInput() {
+ Activity activity = getActivity();
+ if (activity == null) {
+ return null;
+ }
+
if (mCurrentInputUri == null) {
if (mPendingInputUris.isEmpty()) {
// nothing left to do
@@ -548,7 +613,11 @@ public class DecryptListFragment
mCurrentInputUri = mPendingInputUris.remove(0);
}
- Log.d(Constants.TAG, "mInputUri=" + mCurrentInputUri);
+ Log.d(Constants.TAG, "mCurrentInputUri=" + mCurrentInputUri);
+
+ if ( ! checkAndRequestReadPermission(activity, mCurrentInputUri)) {
+ return null;
+ }
PgpDecryptVerifyInputParcel decryptInput = new PgpDecryptVerifyInputParcel()
.setAllowSymmetricDecryption(true);
@@ -556,6 +625,94 @@ public class DecryptListFragment
}
+ /**
+ * Request READ_EXTERNAL_STORAGE permission on Android >= 6.0 to read content from "file" Uris.
+ *
+ * This method returns true on Android < 6, or if permission is already granted. It
+ * requests the permission and returns false otherwise, taking over responsibility
+ * for mCurrentInputUri.
+ *
+ * see https://commonsware.com/blog/2015/10/07/runtime-permissions-files-action-send.html
+ */
+ private boolean checkAndRequestReadPermission(Activity activity, final Uri uri) {
+ if ( ! "file".equals(uri.getScheme())) {
+ return true;
+ }
+
+ if (Build.VERSION.SDK_INT < VERSION_CODES.M) {
+ return true;
+ }
+
+ // Additional check due to https://commonsware.com/blog/2015/11/09/you-cannot-hold-nonexistent-permissions.html
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
+ return true;
+ }
+
+ if (ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+
+ requestPermissions(
+ new String[] { Manifest.permission.READ_EXTERNAL_STORAGE },
+ REQUEST_PERMISSION_READ_EXTERNAL_STORAGE);
+
+ return false;
+
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode,
+ @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+
+ if (requestCode != REQUEST_PERMISSION_READ_EXTERNAL_STORAGE) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ return;
+ }
+
+ boolean permissionWasGranted = grantResults.length > 0
+ && grantResults[0] == PackageManager.PERMISSION_GRANTED;
+
+ if (permissionWasGranted) {
+
+ // permission granted -> retry all cancelled file uris
+ Iterator<Uri> it = mCancelledInputUris.iterator();
+ while (it.hasNext()) {
+ Uri uri = it.next();
+ if ( ! "file".equals(uri.getScheme())) {
+ continue;
+ }
+ it.remove();
+ mPendingInputUris.add(uri);
+ mAdapter.setCancelled(uri, false);
+ }
+
+ } else {
+
+ // permission denied -> cancel current, and all pending file uris
+ mCancelledInputUris.add(mCurrentInputUri);
+ mAdapter.setCancelled(mCurrentInputUri, true);
+
+ mCurrentInputUri = null;
+ Iterator<Uri> it = mPendingInputUris.iterator();
+ while (it.hasNext()) {
+ Uri uri = it.next();
+ if ( ! "file".equals(uri.getScheme())) {
+ continue;
+ }
+ it.remove();
+ mCancelledInputUris.add(uri);
+ mAdapter.setCancelled(uri, true);
+ }
+
+ }
+
+ // hand control flow back
+ cryptoOperation();
+
+ }
+
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
if (mAdapter.mMenuClickedModel == null || !mAdapter.mMenuClickedModel.hasResult()) {
@@ -586,38 +743,83 @@ public class DecryptListFragment
return false;
}
+ private void lookupUnknownKey(final Uri inputUri, long unknownKeyId) {
+
+ final ArrayList<ParcelableKeyRing> keyList;
+ final String keyserver;
+
+ // search config
+ {
+ Preferences prefs = Preferences.getPreferences(getActivity());
+ Preferences.CloudSearchPrefs cloudPrefs =
+ new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver());
+ keyserver = cloudPrefs.keyserver;
+ }
+
+ {
+ ParcelableKeyRing keyEntry = new ParcelableKeyRing(null,
+ KeyFormattingUtils.convertKeyIdToHex(unknownKeyId), null);
+ ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<>();
+ selectedEntries.add(keyEntry);
+
+ keyList = selectedEntries;
+ }
+
+ CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult> callback
+ = new CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult>() {
+
+ @Override
+ public ImportKeyringParcel createOperationInput() {
+ return new ImportKeyringParcel(keyList, keyserver);
+ }
+
+ @Override
+ public void onCryptoOperationSuccess(ImportKeyResult result) {
+ retryUri(inputUri);
+ }
+
+ @Override
+ public void onCryptoOperationCancelled() {
+ mAdapter.setProcessingKeyLookup(inputUri, false);
+ }
+
+ @Override
+ public void onCryptoOperationError(ImportKeyResult result) {
+ result.createNotify(getActivity()).show();
+ mAdapter.setProcessingKeyLookup(inputUri, false);
+ }
+
+ @Override
+ public boolean onCryptoSetProgress(String msg, int progress, int max) {
+ return false;
+ }
+ };
+
+ mAdapter.setProcessingKeyLookup(inputUri, true);
+
+ CryptoOperationHelper importOpHelper = new CryptoOperationHelper<>(2, this, callback, null);
+ importOpHelper.cryptoOperation();
+
+ }
+
+
private void deleteFile(Activity activity, Uri uri) {
// we can only ever delete a file once, if we got this far either it's gone or it will never work
mCanDelete = false;
- if ("file".equals(uri.getScheme())) {
- File file = new File(uri.getPath());
- if (file.delete()) {
+ try {
+ int deleted = FileHelper.deleteFileSecurely(activity, uri);
+ if (deleted > 0) {
Notify.create(activity, R.string.file_delete_ok, Style.OK).show();
} else {
Notify.create(activity, R.string.file_delete_none, Style.WARN).show();
}
- return;
- }
-
- if ("content".equals(uri.getScheme())) {
- try {
- int deleted = activity.getContentResolver().delete(uri, null, null);
- if (deleted > 0) {
- Notify.create(activity, R.string.file_delete_ok, Style.OK).show();
- } else {
- Notify.create(activity, R.string.file_delete_none, Style.WARN).show();
- }
- } catch (Exception e) {
- Log.e(Constants.TAG, "exception deleting file", e);
- Notify.create(activity, R.string.file_delete_exception, Style.ERROR).show();
- }
- return;
+ } catch (Exception e) {
+ Log.e(Constants.TAG, "exception deleting file", e);
+ Notify.create(activity, R.string.file_delete_exception, Style.ERROR).show();
}
- Notify.create(activity, R.string.file_delete_exception, Style.ERROR).show();
-
}
public class DecryptFilesAdapter extends RecyclerView.Adapter<ViewHolder> {
@@ -631,6 +833,7 @@ public class DecryptListFragment
int mProgress, mMax;
String mProgressMsg;
OnClickListener mCancelled;
+ boolean mProcessingKeyLookup;
ViewModel(Uri uri) {
mInputUri = uri;
@@ -639,7 +842,7 @@ public class DecryptListFragment
mCancelled = null;
}
- void addResult(InputDataResult result) {
+ void setResult(InputDataResult result) {
mResult = result;
}
@@ -659,6 +862,10 @@ public class DecryptListFragment
mMax = max;
}
+ void setProcessingKeyLookup(boolean processingKeyLookup) {
+ mProcessingKeyLookup = processingKeyLookup;
+ }
+
// Depends on inputUri only
@Override
public boolean equals(Object o) {
@@ -669,8 +876,10 @@ public class DecryptListFragment
return false;
}
ViewModel viewModel = (ViewModel) o;
- return !(mInputUri != null ? !mInputUri.equals(viewModel.mInputUri)
- : viewModel.mInputUri != null);
+ if (mInputUri == null) {
+ return viewModel.mInputUri == null;
+ }
+ return mInputUri.equals(viewModel.mInputUri);
}
// Depends on inputUri only
@@ -725,17 +934,13 @@ public class DecryptListFragment
}
private void bindItemCancelled(ViewHolder holder, ViewModel model) {
- if (holder.vAnimator.getDisplayedChild() != 3) {
- holder.vAnimator.setDisplayedChild(3);
- }
+ holder.vAnimator.setDisplayedChild(3);
holder.vCancelledRetry.setOnClickListener(model.mCancelled);
}
private void bindItemProgress(ViewHolder holder, ViewModel model) {
- if (holder.vAnimator.getDisplayedChild() != 0) {
- holder.vAnimator.setDisplayedChild(0);
- }
+ holder.vAnimator.setDisplayedChild(0);
holder.vProgress.setProgress(model.mProgress);
holder.vProgress.setMax(model.mMax);
@@ -745,11 +950,10 @@ public class DecryptListFragment
}
private void bindItemSuccess(ViewHolder holder, final ViewModel model) {
- if (holder.vAnimator.getDisplayedChild() != 1) {
- holder.vAnimator.setDisplayedChild(1);
- }
+ holder.vAnimator.setDisplayedChild(1);
- KeyFormattingUtils.setStatus(getResources(), holder, model.mResult.mDecryptVerifyResult);
+ KeyFormattingUtils.setStatus(getResources(), holder,
+ model.mResult.mDecryptVerifyResult, model.mProcessingKeyLookup);
int numFiles = model.mResult.getOutputUris().size();
holder.resizeFileList(numFiles, LayoutInflater.from(getActivity()));
@@ -762,11 +966,14 @@ public class DecryptListFragment
String filename;
if (metadata == null) {
filename = getString(R.string.filename_unknown);
- } else if (TextUtils.isEmpty(metadata.getFilename())) {
- filename = getString("text/plain".equals(metadata.getMimeType())
- ? R.string.filename_unknown_text : R.string.filename_unknown);
- } else {
+ } else if ( ! TextUtils.isEmpty(metadata.getFilename())) {
filename = metadata.getFilename();
+ } else if (ClipDescription.compareMimeTypes(metadata.getMimeType(), Constants.MIME_TYPE_KEYS)) {
+ filename = getString(R.string.filename_keys);
+ } else if (ClipDescription.compareMimeTypes(metadata.getMimeType(), "text/plain")) {
+ filename = getString(R.string.filename_unknown_text);
+ } else {
+ filename = getString(R.string.filename_unknown);
}
fileHolder.vFilename.setText(filename);
@@ -824,6 +1031,13 @@ public class DecryptListFragment
activity.startActivity(intent);
}
});
+ } else {
+ holder.vSignatureLayout.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ lookupUnknownKey(model.mInputUri, keyId);
+ }
+ });
}
}
@@ -852,9 +1066,7 @@ public class DecryptListFragment
}
private void bindItemFailure(ViewHolder holder, final ViewModel model) {
- if (holder.vAnimator.getDisplayedChild() != 2) {
- holder.vAnimator.setDisplayedChild(2);
- }
+ holder.vAnimator.setDisplayedChild(2);
holder.vErrorMsg.setText(model.mResult.getLog().getLast().mType.getMsgId());
@@ -903,21 +1115,44 @@ public class DecryptListFragment
notifyItemChanged(pos);
}
- public void setCancelled(Uri uri, OnClickListener retryListener) {
+ public void setCancelled(final Uri uri, boolean isCancelled) {
ViewModel newModel = new ViewModel(uri);
int pos = mDataset.indexOf(newModel);
- mDataset.get(pos).setCancelled(retryListener);
+ if (isCancelled) {
+ mDataset.get(pos).setCancelled(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ retryUri(uri);
+ }
+ });
+ } else {
+ mDataset.get(pos).setCancelled(null);
+ }
notifyItemChanged(pos);
}
- public void addResult(Uri uri, InputDataResult result) {
+ public void setProcessingKeyLookup(Uri uri, boolean processingKeyLookup) {
+ ViewModel newModel = new ViewModel(uri);
+ int pos = mDataset.indexOf(newModel);
+ mDataset.get(pos).setProcessingKeyLookup(processingKeyLookup);
+ notifyItemChanged(pos);
+ }
+ public void addResult(Uri uri, InputDataResult result) {
ViewModel model = new ViewModel(uri);
int pos = mDataset.indexOf(model);
model = mDataset.get(pos);
+ model.setResult(result);
+ notifyItemChanged(pos);
+ }
- model.addResult(result);
-
+ public void resetItemData(Uri uri) {
+ ViewModel model = new ViewModel(uri);
+ int pos = mDataset.indexOf(model);
+ model = mDataset.get(pos);
+ model.setResult(null);
+ model.setCancelled(null);
+ model.setProcessingKeyLookup(false);
notifyItemChanged(pos);
}
@@ -941,7 +1176,7 @@ public class DecryptListFragment
public View vSignatureLayout;
public TextView vSignatureName;
public TextView vSignatureMail;
- public TextView vSignatureAction;
+ public ViewAnimator vSignatureAction;
public View vContextMenu;
public TextView vErrorMsg;
@@ -984,7 +1219,7 @@ public class DecryptListFragment
vSignatureLayout = itemView.findViewById(R.id.result_signature_layout);
vSignatureName = (TextView) itemView.findViewById(R.id.result_signature_name);
vSignatureMail= (TextView) itemView.findViewById(R.id.result_signature_email);
- vSignatureAction = (TextView) itemView.findViewById(R.id.result_signature_action);
+ vSignatureAction = (ViewAnimator) itemView.findViewById(R.id.result_signature_action);
vFileList = (LinearLayout) itemView.findViewById(R.id.file_list);
for (int i = 0; i < vFileList.getChildCount(); i++) {
@@ -1048,7 +1283,7 @@ public class DecryptListFragment
}
@Override
- public TextView getSignatureAction() {
+ public ViewAnimator getSignatureAction() {
return vSignatureAction;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java
index 4bcca09f1..2fa1aa1c2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextActivity.java
@@ -28,9 +28,12 @@ import android.support.v4.app.Fragment;
import android.widget.Toast;
import org.openintents.openpgp.OpenPgpMetadata;
+import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
+import org.sufficientlysecure.keychain.ui.util.Notify;
+import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.FileHelper;
public class DisplayTextActivity extends BaseActivity {
@@ -73,6 +76,11 @@ public class DisplayTextActivity extends BaseActivity {
}
if (plaintext != null) {
+ if (plaintext.length() > Constants.TEXT_LENGTH_LIMIT) {
+ plaintext = plaintext.substring(0, Constants.TEXT_LENGTH_LIMIT);
+ Notify.create(this, R.string.snack_text_too_long, Style.WARN).show();
+ }
+
loadFragment(plaintext, result);
} else {
Toast.makeText(this, R.string.error_invalid_data, Toast.LENGTH_LONG).show();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java
index dc06e9115..1060714f0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DisplayTextFragment.java
@@ -36,7 +36,6 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
-import org.sufficientlysecure.keychain.util.ShareHelper;
public class DisplayTextFragment extends DecryptFragment {
@@ -60,22 +59,6 @@ public class DisplayTextFragment extends DecryptFragment {
return frag;
}
- /**
- * Create Intent Chooser but exclude decrypt activites
- */
- private Intent sendWithChooserExcludingDecrypt(String text) {
- Intent prototype = createSendIntent(text);
- String title = getString(R.string.title_share_message);
-
- // we don't want to decrypt the decrypted, no inception ;)
- String[] blacklist = new String[]{
- Constants.PACKAGE_NAME + ".ui.DecryptActivity",
- "org.thialfihar.android.apg.ui.DecryptActivity"
- };
-
- return new ShareHelper(getActivity()).createChooserExcluding(prototype, title, blacklist);
- }
-
private Intent createSendIntent(String text) {
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, text);
@@ -146,7 +129,8 @@ public class DisplayTextFragment extends DecryptFragment {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.decrypt_share: {
- startActivity(sendWithChooserExcludingDecrypt(mText.getText().toString()));
+ startActivity(Intent.createChooser(createSendIntent(mText.getText().toString()),
+ getString(R.string.title_share_message)));
break;
}
case R.id.decrypt_copy: {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptFragment.java
index 84660ca7a..89ea6165b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptFragment.java
@@ -25,7 +25,6 @@ import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
@@ -42,7 +41,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker;
import org.sufficientlysecure.keychain.util.FileHelper;
-public class EncryptDecryptOverviewFragment extends Fragment {
+public class EncryptDecryptFragment extends Fragment {
View mClipboardIcon;
@@ -56,7 +55,7 @@ public class EncryptDecryptOverviewFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.encrypt_decrypt_overview_fragment, container, false);
+ View view = inflater.inflate(R.layout.encrypt_decrypt_fragment, container, false);
View mEncryptFile = view.findViewById(R.id.encrypt_files);
View mEncryptText = view.findViewById(R.id.encrypt_text);
@@ -83,7 +82,7 @@ public class EncryptDecryptOverviewFragment extends Fragment {
mDecryptFile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- FileHelper.openDocument(EncryptDecryptOverviewFragment.this, null, "*/*", false, REQUEST_CODE_INPUT);
+ FileHelper.openDocument(EncryptDecryptFragment.this, null, "*/*", false, REQUEST_CODE_INPUT);
}
});
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java
index 8572a5712..ff1b9d478 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java
@@ -25,6 +25,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
@@ -34,6 +35,7 @@ import android.graphics.Bitmap;
import android.graphics.Point;
import android.net.Uri;
import android.os.Build;
+import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v7.widget.DefaultItemAnimator;
@@ -55,7 +57,7 @@ import org.sufficientlysecure.keychain.operations.results.SignEncryptResult;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants;
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
-import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
+import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.adapter.SpacesItemDecoration;
import org.sufficientlysecure.keychain.ui.base.CachingCryptoOperationFragment;
@@ -68,7 +70,6 @@ import org.sufficientlysecure.keychain.util.FileHelper;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.Preferences;
-import org.sufficientlysecure.keychain.util.ShareHelper;
public class EncryptFilesFragment
extends CachingCryptoOperationFragment<SignEncryptParcel, SignEncryptResult> {
@@ -216,6 +217,7 @@ public class EncryptFilesFragment
mSelectedFiles.requestFocus();
}
+ @TargetApi(VERSION_CODES.KITKAT)
private void showOutputFileDialog() {
if (mFilesAdapter.getModelCount() != 1) {
throw new IllegalStateException();
@@ -224,9 +226,7 @@ public class EncryptFilesFragment
String targetName =
(mEncryptFilenames ? "1" : FileHelper.getFilename(getActivity(), model.inputUri))
+ (mUseArmor ? Constants.FILE_EXTENSION_ASC : Constants.FILE_EXTENSION_PGP_MAIN);
- Uri inputUri = model.inputUri;
- FileHelper.saveDocument(this, targetName, inputUri,
- R.string.title_encrypt_to_file, R.string.specify_file_to_encrypt_to, REQUEST_CODE_OUTPUT);
+ FileHelper.saveDocument(this, targetName, REQUEST_CODE_OUTPUT);
}
public void addFile(Intent data) {
@@ -308,6 +308,17 @@ public class EncryptFilesFragment
return true;
}
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+
+ // Show save only on Android >= 4.4 (Document Provider)
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ MenuItem save = menu.findItem(R.id.encrypt_save);
+ save.setVisible(false);
+ }
+ }
+
public void toggleUseArmor(MenuItem item, final boolean useArmor) {
mUseArmor = useArmor;
@@ -393,7 +404,7 @@ public class EncryptFilesFragment
public void onDeleted() {
if (mAfterEncryptAction == AfterEncryptAction.SHARE) {
// Share encrypted message/file
- startActivity(sendWithChooserExcludingEncrypt());
+ startActivity(Intent.createChooser(createSendIntent(), getString(R.string.title_share_file)));
} else {
Activity activity = getActivity();
if (activity == null) {
@@ -413,7 +424,7 @@ public class EncryptFilesFragment
case SHARE:
// Share encrypted message/file
- startActivity(sendWithChooserExcludingEncrypt());
+ startActivity(Intent.createChooser(createSendIntent(), getString(R.string.title_share_file)));
break;
case COPY:
@@ -455,7 +466,7 @@ public class EncryptFilesFragment
String targetName = (mEncryptFilenames
? String.valueOf(filenameCounter) : FileHelper.getFilename(getActivity(), model.inputUri))
+ (mUseArmor ? Constants.FILE_EXTENSION_ASC : Constants.FILE_EXTENSION_PGP_MAIN);
- mOutputUris.add(TemporaryStorageProvider.createFile(getActivity(), targetName));
+ mOutputUris.add(TemporaryFileProvider.createFile(getActivity(), targetName));
filenameCounter++;
}
return false;
@@ -478,7 +489,7 @@ public class EncryptFilesFragment
String targetName = (mEncryptFilenames
? String.valueOf(1) : FileHelper.getFilename(getActivity(),
mFilesAdapter.getModelItem(0).inputUri)) + Constants.FILE_EXTENSION_ASC;
- mOutputUris.add(TemporaryStorageProvider.createFile(getActivity(), targetName, "text/plain"));
+ mOutputUris.add(TemporaryFileProvider.createFile(getActivity(), targetName, "text/plain"));
return false;
}
@@ -587,22 +598,6 @@ public class EncryptFilesFragment
return data;
}
- /**
- * Create Intent Chooser but exclude OK's EncryptActivity.
- */
- private Intent sendWithChooserExcludingEncrypt() {
- Intent prototype = createSendIntent();
- String title = getString(R.string.title_share_file);
-
- // we don't want to encrypt the encrypted, no inception ;)
- String[] blacklist = new String[]{
- Constants.PACKAGE_NAME + ".ui.EncryptFilesActivity",
- "org.thialfihar.android.apg.ui.EncryptActivity"
- };
-
- return new ShareHelper(getActivity()).createChooserExcluding(prototype, title, blacklist);
- }
-
private Intent createSendIntent() {
Intent sendIntent;
// file
@@ -613,7 +608,7 @@ public class EncryptFilesFragment
sendIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
sendIntent.putExtra(Intent.EXTRA_STREAM, mOutputUris);
}
- sendIntent.setType(Constants.ENCRYPTED_FILES_MIME);
+ sendIntent.setType(Constants.MIME_TYPE_ENCRYPTED_ALTERNATE);
EncryptActivity modeInterface = (EncryptActivity) getActivity();
EncryptModeFragment modeFragment = modeInterface.getModeFragment();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
index a849cdf12..50dbc9a8b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java
@@ -18,14 +18,23 @@
package org.sufficientlysecure.keychain.ui;
+
+import java.io.IOException;
+
import android.app.Activity;
import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
-import android.view.View;
+import android.widget.Toast;
+import org.apache.james.mime4j.util.MimeUtil;
+import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.intents.OpenKeychainIntents;
+import org.sufficientlysecure.keychain.ui.util.Notify;
+import org.sufficientlysecure.keychain.ui.util.Notify.Style;
+import org.sufficientlysecure.keychain.util.FileHelper;
import org.sufficientlysecure.keychain.util.Log;
public class EncryptTextActivity extends EncryptActivity {
@@ -51,23 +60,71 @@ public class EncryptTextActivity extends EncryptActivity {
extras = new Bundle();
}
+ String textData = extras.getString(EXTRA_TEXT);
+ boolean returnProcessText = false;
+
// When sending to OpenKeychain Encrypt via share menu
if (Intent.ACTION_SEND.equals(action) && type != null) {
Log.logDebugBundle(extras, "extras");
// When sending to OpenKeychain Encrypt via share menu
- if ("text/plain".equals(type)) {
- String sharedText = extras.getString(Intent.EXTRA_TEXT);
- if (sharedText != null) {
- // handle like normal text encryption, override action and extras to later
- // executeServiceMethod ACTION_ENCRYPT_TEXT in main actions
- extras.putString(EXTRA_TEXT, sharedText);
+ if ( ! MimeUtil.isSameMimeType("text/plain", type)) {
+ Toast.makeText(this, R.string.toast_wrong_mimetype, Toast.LENGTH_LONG).show();
+ finish();
+ return;
+ }
+
+ String sharedText;
+ if (extras.containsKey(Intent.EXTRA_TEXT)) {
+ sharedText = extras.getString(Intent.EXTRA_TEXT);
+ } else if (extras.containsKey(Intent.EXTRA_STREAM)) {
+ try {
+ sharedText = FileHelper.readTextFromUri(this, extras.<Uri>getParcelable(Intent.EXTRA_STREAM), null);
+ } catch (IOException e) {
+ Toast.makeText(this, R.string.error_preparing_data, Toast.LENGTH_LONG).show();
+ finish();
+ return;
}
+ } else {
+ Toast.makeText(this, R.string.toast_no_text, Toast.LENGTH_LONG).show();
+ finish();
+ return;
+ }
+ if (sharedText != null) {
+ if (sharedText.length() > Constants.TEXT_LENGTH_LIMIT) {
+ sharedText = sharedText.substring(0, Constants.TEXT_LENGTH_LIMIT);
+ Notify.create(this, R.string.snack_shared_text_too_long, Style.WARN).show();
+ }
+ // handle like normal text encryption, override action and extras to later
+ // executeServiceMethod ACTION_ENCRYPT_TEXT in main actions
+ textData = sharedText;
+ }
+
+ }
+
+ // Android 6, PROCESS_TEXT Intent
+ if (Intent.ACTION_PROCESS_TEXT.equals(action) && type != null) {
+
+ String sharedText = null;
+ if (extras.containsKey(Intent.EXTRA_PROCESS_TEXT)) {
+ sharedText = extras.getString(Intent.EXTRA_PROCESS_TEXT);
+ returnProcessText = true;
+ } else if (extras.containsKey(Intent.EXTRA_PROCESS_TEXT_READONLY)) {
+ sharedText = extras.getString(Intent.EXTRA_PROCESS_TEXT_READONLY);
+ }
+
+ if (sharedText != null) {
+ if (sharedText.length() > Constants.TEXT_LENGTH_LIMIT) {
+ sharedText = sharedText.substring(0, Constants.TEXT_LENGTH_LIMIT);
+ Notify.create(this, R.string.snack_shared_text_too_long, Style.WARN).show();
+ }
+ // handle like normal text encryption, override action and extras to later
+ // executeServiceMethod ACTION_ENCRYPT_TEXT in main actions
+ textData = sharedText;
}
}
- String textData = extras.getString(EXTRA_TEXT);
if (textData == null) {
textData = "";
}
@@ -75,7 +132,7 @@ public class EncryptTextActivity extends EncryptActivity {
if (savedInstanceState == null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
- EncryptTextFragment encryptFragment = EncryptTextFragment.newInstance(textData);
+ EncryptTextFragment encryptFragment = EncryptTextFragment.newInstance(textData, returnProcessText);
transaction.replace(R.id.encrypt_text_container, encryptFragment);
transaction.commit();
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java
index ab676285e..10d88253d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java
@@ -46,7 +46,6 @@ import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.Preferences;
-import org.sufficientlysecure.keychain.util.ShareHelper;
import java.util.Date;
import java.util.HashSet;
@@ -57,8 +56,10 @@ public class EncryptTextFragment
public static final String ARG_TEXT = "text";
public static final String ARG_USE_COMPRESSION = "use_compression";
+ public static final String ARG_RETURN_PROCESS_TEXT = "return_process_text";
private boolean mShareAfterEncrypt;
+ private boolean mReturnProcessTextAfterEncrypt;
private boolean mUseCompression;
private boolean mHiddenRecipients = false;
@@ -67,11 +68,12 @@ public class EncryptTextFragment
/**
* Creates new instance of this fragment
*/
- public static EncryptTextFragment newInstance(String text) {
+ public static EncryptTextFragment newInstance(String text, boolean returnProcessTextAfterEncrypt) {
EncryptTextFragment frag = new EncryptTextFragment();
Bundle args = new Bundle();
args.putString(ARG_TEXT, text);
+ args.putBoolean(ARG_RETURN_PROCESS_TEXT, returnProcessTextAfterEncrypt);
frag.setArguments(args);
return frag;
@@ -129,6 +131,7 @@ public class EncryptTextFragment
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
mMessage = getArguments().getString(ARG_TEXT);
+ mReturnProcessTextAfterEncrypt = getArguments().getBoolean(ARG_RETURN_PROCESS_TEXT, false);
}
Preferences prefs = Preferences.getPreferences(getActivity());
@@ -152,6 +155,12 @@ public class EncryptTextFragment
inflater.inflate(R.menu.encrypt_text_fragment, menu);
menu.findItem(R.id.check_enable_compression).setChecked(mUseCompression);
+
+ if (mReturnProcessTextAfterEncrypt) {
+ menu.findItem(R.id.encrypt_paste).setVisible(true);
+ menu.findItem(R.id.encrypt_copy).setVisible(false);
+ menu.findItem(R.id.encrypt_share).setVisible(false);
+ }
}
@Override
@@ -178,6 +187,11 @@ public class EncryptTextFragment
cryptoOperation(new CryptoInputParcel(new Date()));
break;
}
+ case R.id.encrypt_paste: {
+ hideKeyboard();
+ cryptoOperation(new CryptoInputParcel(new Date()));
+ break;
+ }
default: {
return super.onOptionsItemSelected(item);
}
@@ -289,26 +303,10 @@ public class EncryptTextFragment
result.createNotify(activity).show();
}
- /**
- * Create Intent Chooser but exclude OK's EncryptActivity.
- */
- private Intent sendWithChooserExcludingEncrypt(byte[] resultBytes) {
- Intent prototype = createSendIntent(resultBytes);
- String title = getString(R.string.title_share_message);
-
- // we don't want to encrypt the encrypted, no inception ;)
- String[] blacklist = new String[]{
- Constants.PACKAGE_NAME + ".ui.EncryptTextActivity",
- "org.thialfihar.android.apg.ui.EncryptActivity"
- };
-
- return new ShareHelper(getActivity()).createChooserExcluding(prototype, title, blacklist);
- }
-
private Intent createSendIntent(byte[] resultBytes) {
Intent sendIntent;
sendIntent = new Intent(Intent.ACTION_SEND);
- sendIntent.setType(Constants.ENCRYPTED_TEXT_MIME);
+ sendIntent.setType(Constants.MIME_TYPE_TEXT);
sendIntent.putExtra(Intent.EXTRA_TEXT, new String(resultBytes));
EncryptActivity modeInterface = (EncryptActivity) getActivity();
@@ -343,7 +341,13 @@ public class EncryptTextFragment
if (mShareAfterEncrypt) {
// Share encrypted message/file
- startActivity(sendWithChooserExcludingEncrypt(result.getResultBytes()));
+ startActivity(Intent.createChooser(createSendIntent(result.getResultBytes()),
+ getString(R.string.title_share_message)));
+ } else if (mReturnProcessTextAfterEncrypt) {
+ Intent resultIntent = new Intent();
+ resultIntent.putExtra(Intent.EXTRA_PROCESS_TEXT, new String(result.getResultBytes()));
+ getActivity().setResult(Activity.RESULT_OK, resultIntent);
+ getActivity().finish();
} else {
// Copy to clipboard
copyToClipboard(result);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
index 4ef6c40dc..7f7532ddf 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
@@ -21,8 +21,8 @@ import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Message;
import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -33,10 +33,8 @@ import org.sufficientlysecure.keychain.intents.OpenKeychainIntents;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
-import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
-import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify;
@@ -78,10 +76,8 @@ public class ImportKeysActivity extends BaseNfcActivity
public static final String EXTRA_PENDING_INTENT_DATA = "data";
private Intent mPendingIntentData;
- // view
- private ImportKeysListFragment mListFragment;
- private Fragment mTopFragment;
- private View mImportButton;
+ public static final String TAG_FRAG_LIST = "frag_list";
+ public static final String TAG_FRAG_TOP = "frag_top";
// for CryptoOperationHelper.Callback
private String mKeyserver;
@@ -94,15 +90,22 @@ public class ImportKeysActivity extends BaseNfcActivity
super.onCreate(savedInstanceState);
setFullScreenDialogClose(Activity.RESULT_CANCELED, true);
- mImportButton = findViewById(R.id.import_import);
- mImportButton.setOnClickListener(new OnClickListener() {
+ findViewById(R.id.import_import).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- importKeys();
+ importSelectedKeys();
}
});
- handleActions(savedInstanceState, getIntent());
+ // only used for OpenPgpService
+ if (getIntent().hasExtra(EXTRA_PENDING_INTENT_DATA)) {
+ mPendingIntentData = getIntent().getParcelableExtra(EXTRA_PENDING_INTENT_DATA);
+ }
+
+ // if we aren't being restored, initialize fragments
+ if (savedInstanceState == null) {
+ handleActions(getIntent());
+ }
}
@Override
@@ -110,7 +113,7 @@ public class ImportKeysActivity extends BaseNfcActivity
setContentView(R.layout.import_keys_activity);
}
- protected void handleActions(Bundle savedInstanceState, Intent intent) {
+ protected void handleActions(Intent intent) {
String action = intent.getAction();
Bundle extras = intent.getExtras();
Uri dataUri = intent.getData();
@@ -120,14 +123,8 @@ public class ImportKeysActivity extends BaseNfcActivity
extras = new Bundle();
}
- if (action == null) {
- startCloudFragment(savedInstanceState, null, false, null);
- startListFragment(savedInstanceState, null, null, null, null);
- return;
- }
-
if (Intent.ACTION_VIEW.equals(action)) {
- if (scheme.equals("http") || scheme.equals("https")) {
+ if ("http".equals(scheme) || "https".equals(scheme)) {
action = ACTION_SEARCH_KEYSERVER_FROM_URL;
} else {
// Android's Action when opening file associated to Keychain (see AndroidManifest.xml)
@@ -135,20 +132,24 @@ public class ImportKeysActivity extends BaseNfcActivity
action = ACTION_IMPORT_KEY;
}
}
+ if (action == null) {
+ // -> switch to default below
+ action = "";
+ }
switch (action) {
case ACTION_IMPORT_KEY: {
- /* Keychain's own Actions */
- startFileFragment(savedInstanceState);
-
if (dataUri != null) {
// action: directly load data
- startListFragment(savedInstanceState, null, dataUri, null, null);
+ startListFragment(null, dataUri, null, null);
} else if (extras.containsKey(EXTRA_KEY_BYTES)) {
byte[] importData = extras.getByteArray(EXTRA_KEY_BYTES);
// action: directly load data
- startListFragment(savedInstanceState, importData, null, null, null);
+ startListFragment(importData, null, null, null);
+ } else {
+ startTopFileFragment();
+ startListFragment(null, null, null, null);
}
break;
}
@@ -156,10 +157,6 @@ public class ImportKeysActivity extends BaseNfcActivity
case ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE:
case ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT: {
- // only used for OpenPgpService
- if (extras.containsKey(EXTRA_PENDING_INTENT_DATA)) {
- mPendingIntentData = extras.getParcelable(EXTRA_PENDING_INTENT_DATA);
- }
if (extras.containsKey(EXTRA_QUERY) || extras.containsKey(EXTRA_KEY_ID)) {
/* simple search based on query or key id */
@@ -175,10 +172,10 @@ public class ImportKeysActivity extends BaseNfcActivity
if (query != null && query.length() > 0) {
// display keyserver fragment with query
- startCloudFragment(savedInstanceState, query, false, null);
+ startTopCloudFragment(query, false, null);
// action: search immediately
- startListFragment(savedInstanceState, null, null, query, null);
+ startListFragment(null, null, query, null);
} else {
Log.e(Constants.TAG, "Query is empty!");
return;
@@ -194,10 +191,10 @@ public class ImportKeysActivity extends BaseNfcActivity
String query = "0x" + fingerprint;
// display keyserver fragment with query
- startCloudFragment(savedInstanceState, query, true, null);
+ startTopCloudFragment(query, true, null);
// action: search immediately
- startListFragment(savedInstanceState, null, null, query, null);
+ startListFragment(null, null, query, null);
}
} else {
Log.e(Constants.TAG,
@@ -208,14 +205,6 @@ public class ImportKeysActivity extends BaseNfcActivity
}
break;
}
- case ACTION_IMPORT_KEY_FROM_FILE: {
- // NOTE: this only displays the appropriate fragment, no actions are taken
- startFileFragment(savedInstanceState);
-
- // no immediate actions!
- startListFragment(savedInstanceState, null, null, null, null);
- break;
- }
case ACTION_SEARCH_KEYSERVER_FROM_URL: {
// need to process URL to get search query and keyserver authority
String query = dataUri.getQueryParameter("search");
@@ -223,120 +212,88 @@ public class ImportKeysActivity extends BaseNfcActivity
// if query not specified, we still allow users to search the keyserver in the link
if (query == null) {
Notify.create(this, R.string.import_url_warn_no_search_parameter, Notify.LENGTH_INDEFINITE,
- Notify.Style.WARN).show(mTopFragment);
+ Notify.Style.WARN).show();
// we just set the keyserver
- startCloudFragment(savedInstanceState, null, false, keyserver);
+ startTopCloudFragment(null, false, keyserver);
// we don't set the keyserver for ImportKeysListFragment since
// it'll be set in the cloudSearchPrefs of ImportKeysCloudFragment
// which is used when the user clicks on the search button
- startListFragment(savedInstanceState, null, null, null, null);
+ startListFragment(null, null, null, null);
} else {
// we allow our users to edit the query if they wish
- startCloudFragment(savedInstanceState, query, false, keyserver);
+ startTopCloudFragment(query, false, keyserver);
// search immediately
- startListFragment(savedInstanceState, null, null, query, keyserver);
+ startListFragment(null, null, query, keyserver);
}
break;
}
+ case ACTION_IMPORT_KEY_FROM_FILE:
case ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN: {
// NOTE: this only displays the appropriate fragment, no actions are taken
- startFileFragment(savedInstanceState);
-
- // no immediate actions!
- startListFragment(savedInstanceState, null, null, null, null);
+ startTopFileFragment();
+ startListFragment(null, null, null, null);
break;
}
default: {
- startCloudFragment(savedInstanceState, null, false, null);
- startListFragment(savedInstanceState, null, null, null, null);
+ startTopCloudFragment(null, false, null);
+ startListFragment(null, null, null, null);
break;
}
}
}
+ @Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+
+ // the only thing we need to take care of for restoring state is
+ // that the top layout is shown iff it contains a fragment
+ Fragment topFragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAG_TOP);
+ boolean hasTopFragment = topFragment != null;
+ findViewById(R.id.import_keys_top_layout).setVisibility(hasTopFragment ? View.VISIBLE : View.GONE);
+ }
/**
* if the fragment is started with non-null bytes/dataUri/serverQuery, it will immediately
* load content
*
- * @param savedInstanceState
* @param bytes bytes containing list of keyrings to import
* @param dataUri uri to file to import keyrings from
* @param serverQuery query to search for on the keyserver
* @param keyserver keyserver authority to search on. If null will use keyserver from
* user preferences
*/
- private void startListFragment(Bundle savedInstanceState, byte[] bytes, Uri dataUri,
- String serverQuery, String keyserver) {
- // However, if we're being restored from a previous state,
- // then we don't need to do anything and should return or else
- // we could end up with overlapping fragments.
- if (mListFragment != null) {
- return;
- }
-
- mListFragment = ImportKeysListFragment.newInstance(bytes, dataUri, serverQuery, false,
- keyserver);
-
- // Add the fragment to the 'fragment_container' FrameLayout
- // NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
+ private void startListFragment(byte[] bytes, Uri dataUri, String serverQuery, String keyserver) {
+ Fragment listFragment =
+ ImportKeysListFragment.newInstance(bytes, dataUri, serverQuery, false, keyserver);
getSupportFragmentManager().beginTransaction()
- .replace(R.id.import_keys_list_container, mListFragment)
- .commitAllowingStateLoss();
- // do it immediately!
- getSupportFragmentManager().executePendingTransactions();
+ .replace(R.id.import_keys_list_container, listFragment, TAG_FRAG_LIST)
+ .commit();
}
- private void startFileFragment(Bundle savedInstanceState) {
- // However, if we're being restored from a previous state,
- // then we don't need to do anything and should return or else
- // we could end up with overlapping fragments.
- if (mTopFragment != null) {
- return;
- }
-
- // Create an instance of the fragment
- mTopFragment = ImportKeysFileFragment.newInstance();
-
- // Add the fragment to the 'fragment_container' FrameLayout
- // NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
+ private void startTopFileFragment() {
+ findViewById(R.id.import_keys_top_layout).setVisibility(View.VISIBLE);
+ Fragment importFileFragment = ImportKeysFileFragment.newInstance();
getSupportFragmentManager().beginTransaction()
- .replace(R.id.import_keys_top_container, mTopFragment)
- .commitAllowingStateLoss();
- // do it immediately!
- getSupportFragmentManager().executePendingTransactions();
+ .replace(R.id.import_keys_top_container, importFileFragment, TAG_FRAG_TOP)
+ .commit();
}
/**
* loads the CloudFragment, which consists of the search bar, search button and settings icon
* visually.
*
- * @param savedInstanceState
* @param query search query
* @param disableQueryEdit if true, user will not be able to edit the search query
* @param keyserver keyserver authority to use for search, if null will use keyserver
* specified in user preferences
*/
-
- private void startCloudFragment(Bundle savedInstanceState, String query, boolean disableQueryEdit, String
- keyserver) {
- // However, if we're being restored from a previous state,
- // then we don't need to do anything and should return or else
- // we could end up with overlapping fragments.
- if (mTopFragment != null) {
- return;
- }
-
- // Create an instance of the fragment
- mTopFragment = ImportKeysCloudFragment.newInstance(query, disableQueryEdit, keyserver);
-
- // Add the fragment to the 'fragment_container' FrameLayout
- // NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
+ private void startTopCloudFragment(String query, boolean disableQueryEdit, String keyserver) {
+ findViewById(R.id.import_keys_top_layout).setVisibility(View.VISIBLE);
+ Fragment importCloudFragment = ImportKeysCloudFragment.newInstance(query, disableQueryEdit, keyserver);
getSupportFragmentManager().beginTransaction()
- .replace(R.id.import_keys_top_container, mTopFragment)
- .commitAllowingStateLoss();
- // do it immediately!
- getSupportFragmentManager().executePendingTransactions();
+ .replace(R.id.import_keys_top_container, importCloudFragment, TAG_FRAG_TOP)
+ .commit();
}
private boolean isFingerprintValid(String fingerprint) {
@@ -350,63 +307,32 @@ public class ImportKeysActivity extends BaseNfcActivity
}
public void loadCallback(final ImportKeysListFragment.LoaderState loaderState) {
- mListFragment.loadNew(loaderState);
+ FragmentManager fragMan = getSupportFragmentManager();
+ ImportKeysListFragment keyListFragment = (ImportKeysListFragment) fragMan.findFragmentByTag(TAG_FRAG_LIST);
+ keyListFragment.loadNew(loaderState);
}
- private void handleMessage(Message message) {
- if (message.arg1 == ServiceProgressHandler.MessageStatus.OKAY.ordinal()) {
- // get returned data bundle
- Bundle returnData = message.getData();
- if (returnData == null) {
- return;
- }
- final ImportKeyResult result =
- returnData.getParcelable(OperationResult.EXTRA_RESULT);
- if (result == null) {
- Log.e(Constants.TAG, "result == null");
- return;
- }
+ private void importSelectedKeys() {
- if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(getIntent().getAction())
- || ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(getIntent().getAction())) {
- Intent intent = new Intent();
- intent.putExtra(ImportKeyResult.EXTRA_RESULT, result);
- ImportKeysActivity.this.setResult(RESULT_OK, intent);
- ImportKeysActivity.this.finish();
- return;
- }
- if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE.equals(getIntent().getAction())) {
- ImportKeysActivity.this.setResult(RESULT_OK, mPendingIntentData);
- ImportKeysActivity.this.finish();
- return;
- }
-
- result.createNotify(ImportKeysActivity.this)
- .show((ViewGroup) findViewById(R.id.import_snackbar));
- }
- }
+ FragmentManager fragMan = getSupportFragmentManager();
+ ImportKeysListFragment keyListFragment = (ImportKeysListFragment) fragMan.findFragmentByTag(TAG_FRAG_LIST);
- /**
- * Import keys with mImportData
- */
- public void importKeys() {
-
- if (mListFragment.getSelectedEntries().size() == 0) {
+ if (keyListFragment.getSelectedEntries().size() == 0) {
Notify.create(this, R.string.error_nothing_import_selected, Notify.Style.ERROR)
.show((ViewGroup) findViewById(R.id.import_snackbar));
return;
}
- mOperationHelper = new CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult>(
+ mOperationHelper = new CryptoOperationHelper<>(
1, this, this, R.string.progress_importing
);
- ImportKeysListFragment.LoaderState ls = mListFragment.getLoaderState();
+ ImportKeysListFragment.LoaderState ls = keyListFragment.getLoaderState();
if (ls instanceof ImportKeysListFragment.BytesLoaderState) {
Log.d(Constants.TAG, "importKeys started");
// get DATA from selected key entries
- IteratorWithSize<ParcelableKeyRing> selectedEntries = mListFragment.getSelectedData();
+ IteratorWithSize<ParcelableKeyRing> selectedEntries = keyListFragment.getSelectedData();
// instead of giving the entries by Intent extra, cache them into a
// file to prevent Java Binder problems on heavy imports
@@ -435,7 +361,7 @@ public class ImportKeysActivity extends BaseNfcActivity
ArrayList<ParcelableKeyRing> keys = new ArrayList<>();
{
// change the format into ParcelableKeyRing
- ArrayList<ImportKeysListEntry> entries = mListFragment.getSelectedEntries();
+ ArrayList<ImportKeysListEntry> entries = keyListFragment.getSelectedEntries();
for (ImportKeysListEntry entry : entries) {
keys.add(new ParcelableKeyRing(
entry.getFingerprintHex(), entry.getKeyIdHex(), entry.getExtraData())
@@ -451,31 +377,35 @@ public class ImportKeysActivity extends BaseNfcActivity
}
@Override
- protected void onNfcPostExecute() throws IOException {
+ protected void onNfcPostExecute() {
// either way, finish after NFC AsyncTask
finish();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (mOperationHelper == null ||
- !mOperationHelper.handleActivityResult(requestCode, resultCode, data)) {
- super.onActivityResult(requestCode, resultCode, data);
+ if (mOperationHelper != null &&
+ mOperationHelper.handleActivityResult(requestCode, resultCode, data)) {
+ return;
}
+ super.onActivityResult(requestCode, resultCode, data);
}
public void handleResult(ImportKeyResult result) {
- if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(getIntent().getAction())
- || ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(getIntent().getAction())) {
+ String intentAction = getIntent().getAction();
+
+ if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(intentAction)
+ || ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(intentAction)) {
Intent intent = new Intent();
intent.putExtra(ImportKeyResult.EXTRA_RESULT, result);
- ImportKeysActivity.this.setResult(RESULT_OK, intent);
- ImportKeysActivity.this.finish();
+ setResult(RESULT_OK, intent);
+ finish();
return;
}
- if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE.equals(getIntent().getAction())) {
- ImportKeysActivity.this.setResult(RESULT_OK, mPendingIntentData);
- ImportKeysActivity.this.finish();
+
+ if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE.equals(intentAction)) {
+ setResult(RESULT_OK, mPendingIntentData);
+ finish();
return;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java
index 746c75600..8de60dfd3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysFileFragment.java
@@ -29,6 +29,9 @@ import android.view.ViewGroup;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
+import org.sufficientlysecure.keychain.pgp.PgpHelper;
+import org.sufficientlysecure.keychain.ui.util.Notify;
+import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.FileHelper;
public class ImportKeysFileFragment extends Fragment {
@@ -78,12 +81,16 @@ public class ImportKeysFileFragment extends Fragment {
String sendText = "";
if (clipboardText != null) {
sendText = clipboardText.toString();
+ sendText = PgpHelper.getPgpKeyContent(sendText);
+ if (sendText == null) {
+ Notify.create(mImportActivity, "Bad data!", Style.ERROR).show();
+ return;
+ }
mImportActivity.loadCallback(new ImportKeysListFragment.BytesLoaderState(sendText.getBytes(), null));
}
}
});
-
return view;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
index 8502798cd..7aed3176c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
@@ -17,6 +17,11 @@
package org.sufficientlysecure.keychain.ui;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
@@ -40,21 +45,12 @@ import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListCloudLoader;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader;
-import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize;
import org.sufficientlysecure.keychain.util.ParcelableProxy;
import org.sufficientlysecure.keychain.util.Preferences;
import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
-import java.io.ByteArrayInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
public class ImportKeysListFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
@@ -179,8 +175,8 @@ public class ImportKeysListFragment extends ListFragment implements
}
static public class BytesLoaderState extends LoaderState {
- byte[] mKeyBytes;
- Uri mDataUri;
+ public byte[] mKeyBytes;
+ public Uri mDataUri;
BytesLoaderState(byte[] keyBytes, Uri dataUri) {
mKeyBytes = keyBytes;
@@ -304,9 +300,7 @@ public class ImportKeysListFragment extends ListFragment implements
onCreateLoader(int id, Bundle args) {
switch (id) {
case LOADER_ID_BYTES: {
- BytesLoaderState ls = (BytesLoaderState) mLoaderState;
- InputData inputData = getInputData(ls.mKeyBytes, ls.mDataUri);
- return new ImportKeysListLoader(mActivity, inputData);
+ return new ImportKeysListLoader(mActivity, (BytesLoaderState) mLoaderState);
}
case LOADER_ID_CLOUD: {
CloudLoaderState ls = (CloudLoaderState) mLoaderState;
@@ -431,24 +425,4 @@ public class ImportKeysListFragment extends ListFragment implements
}
}
- private InputData getInputData(byte[] importBytes, Uri dataUri) {
- InputData inputData = null;
- if (importBytes != null) {
- inputData = new InputData(new ByteArrayInputStream(importBytes), importBytes.length);
- } else if (dataUri != null) {
- try {
- InputStream inputStream = getActivity().getContentResolver().openInputStream(dataUri);
- int length = inputStream.available();
-
- inputData = new InputData(inputStream, length);
- } catch (FileNotFoundException e) {
- Log.e(Constants.TAG, "FileNotFoundException!", e);
- } catch (IOException e) {
- Log.e(Constants.TAG, "IOException!", e);
- }
- }
-
- return inputData;
- }
-
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java
index b60f3984c..45ce604c3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java
@@ -87,12 +87,7 @@ public class ImportKeysProxyActivity extends FragmentActivity
processScannedContent(dataUri);
} else if (ACTION_SCAN_WITH_RESULT.equals(action)
|| ACTION_SCAN_IMPORT.equals(action) || ACTION_QR_CODE_API.equals(action)) {
- IntentIntegrator integrator = new IntentIntegrator(this);
- integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES)
- .setPrompt(getString(R.string.import_qr_code_text))
- .setResultDisplayDuration(0);
- integrator.setOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- integrator.initiateScan();
+ new IntentIntegrator(this).setCaptureActivity(QrCodeCaptureActivity.class).initiateScan();
} else if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
// Check to see if the Activity started due to an Android Beam
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
index 2b6d786d4..db31bd0a1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -30,6 +30,7 @@ import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
@@ -46,14 +47,17 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
+import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
+import android.widget.ViewAnimator;
import com.getbase.floatingactionbutton.FloatingActionButton;
import com.getbase.floatingactionbutton.FloatingActionsMenu;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
+import org.sufficientlysecure.keychain.operations.results.BenchmarkResult;
import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
@@ -61,6 +65,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.BenchmarkInputParcel;
import org.sufficientlysecure.keychain.service.ConsolidateInputParcel;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter;
@@ -98,6 +103,8 @@ public class KeyListFragment extends LoaderFragment
// saves the mode object for multiselect, needed for reset at some point
private ActionMode mActionMode = null;
+ private Button vSearchButton;
+ private ViewAnimator vSearchContainer;
private String mQuery;
private FloatingActionsMenu mFab;
@@ -162,7 +169,9 @@ public class KeyListFragment extends LoaderFragment
super.onActivityCreated(savedInstanceState);
// show app name instead of "keys" from nav drawer
- getActivity().setTitle(R.string.app_name);
+ final FragmentActivity activity = getActivity();
+
+ activity.setTitle(R.string.app_name);
mStickyList.setOnItemClickListener(this);
mStickyList.setAreHeadersSticky(true);
@@ -171,7 +180,7 @@ public class KeyListFragment extends LoaderFragment
// Adds an empty footer view so that the Floating Action Button won't block content
// in last few rows.
- View footer = new View(getActivity());
+ View footer = new View(activity);
int spacing = (int) android.util.TypedValue.applyDimension(
android.util.TypedValue.COMPLEX_UNIT_DIP, 72, getResources().getDisplayMetrics()
@@ -195,7 +204,7 @@ public class KeyListFragment extends LoaderFragment
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- android.view.MenuInflater inflater = getActivity().getMenuInflater();
+ android.view.MenuInflater inflater = activity.getMenuInflater();
inflater.inflate(R.menu.key_list_multi, menu);
mActionMode = mode;
return true;
@@ -235,7 +244,7 @@ public class KeyListFragment extends LoaderFragment
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
- boolean checked) {
+ boolean checked) {
if (checked) {
mAdapter.setNewSelection(position, true);
} else {
@@ -255,8 +264,21 @@ public class KeyListFragment extends LoaderFragment
// Start out with a progress indicator.
setContentShown(false);
+ // this view is made visible if no data is available
+ mStickyList.setEmptyView(activity.findViewById(R.id.key_list_empty));
+
+ // click on search button (in empty view) starts query for search string
+ vSearchContainer = (ViewAnimator) activity.findViewById(R.id.search_container);
+ vSearchButton = (Button) activity.findViewById(R.id.search_button);
+ vSearchButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ startSearchForQuery();
+ }
+ });
+
// Create an empty adapter we will use to display the loaded data.
- mAdapter = new KeyListAdapter(getActivity(), null, 0);
+ mAdapter = new KeyListAdapter(activity, null, 0);
mStickyList.setAdapter(mAdapter);
// Prepare the loader. Either re-connect with an existing one,
@@ -264,8 +286,20 @@ public class KeyListFragment extends LoaderFragment
getLoaderManager().initLoader(0, null, this);
}
+ private void startSearchForQuery() {
+ Activity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+
+ Intent searchIntent = new Intent(activity, ImportKeysActivity.class);
+ searchIntent.putExtra(ImportKeysActivity.EXTRA_QUERY, mQuery);
+ searchIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER);
+ startActivity(searchIntent);
+ }
+
static final String ORDER =
- KeyRings.HAS_ANY_SECRET + " DESC, UPPER(" + KeyRings.USER_ID + ") ASC";
+ KeyRings.HAS_ANY_SECRET + " DESC, " + KeyRings.USER_ID + " COLLATE NOCASE ASC";
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
@@ -319,9 +353,6 @@ public class KeyListFragment extends LoaderFragment
mStickyList.setAdapter(mAdapter);
- // this view is made visible if no data is available
- mStickyList.setEmptyView(getActivity().findViewById(R.id.key_list_empty));
-
// end action mode, if any
if (mActionMode != null) {
mActionMode.finish();
@@ -387,6 +418,7 @@ public class KeyListFragment extends LoaderFragment
if (Constants.DEBUG) {
menu.findItem(R.id.menu_key_list_debug_cons).setVisible(true);
+ menu.findItem(R.id.menu_key_list_debug_bench).setVisible(true);
menu.findItem(R.id.menu_key_list_debug_read).setVisible(true);
menu.findItem(R.id.menu_key_list_debug_write).setVisible(true);
menu.findItem(R.id.menu_key_list_debug_first_time).setVisible(true);
@@ -470,6 +502,10 @@ public class KeyListFragment extends LoaderFragment
consolidate();
return true;
+ case R.id.menu_key_list_debug_bench:
+ benchmark();
+ return true;
+
default:
return super.onOptionsItemSelected(item);
}
@@ -483,17 +519,25 @@ public class KeyListFragment extends LoaderFragment
@Override
public boolean onQueryTextChange(String s) {
Log.d(Constants.TAG, "onQueryTextChange s:" + s);
- // Called when the action bar search text has changed. Update
- // the search filter, and restart the loader to do a new query
- // with this filter.
+ // Called when the action bar search text has changed. Update the
+ // search filter, and restart the loader to do a new query with this
+ // filter.
// If the nav drawer is opened, onQueryTextChange("") is executed.
// This hack prevents restarting the loader.
- // TODO: better way to fix this?
- String tmp = (mQuery == null) ? "" : mQuery;
- if (!s.equals(tmp)) {
+ if (!s.equals(mQuery)) {
mQuery = s;
getLoaderManager().restartLoader(0, null, this);
}
+
+ if (s.length() > 2) {
+ vSearchButton.setText(getString(R.string.btn_search_for_query, mQuery));
+ vSearchContainer.setDisplayedChild(1);
+ vSearchContainer.setVisibility(View.VISIBLE);
+ } else {
+ vSearchContainer.setDisplayedChild(0);
+ vSearchContainer.setVisibility(View.GONE);
+ }
+
return true;
}
@@ -560,8 +604,8 @@ public class KeyListFragment extends LoaderFragment
mKeyserver = cloudPrefs.keyserver;
}
- mImportOpHelper = new CryptoOperationHelper<>(1, this,
- this, R.string.progress_updating);
+ mImportOpHelper = new CryptoOperationHelper<>(1, this, this, R.string.progress_updating);
+ mImportOpHelper.setProgressCancellable(true);
mImportOpHelper.cryptoOperation();
}
@@ -602,6 +646,43 @@ public class KeyListFragment extends LoaderFragment
mConsolidateOpHelper.cryptoOperation();
}
+ private void benchmark() {
+
+ CryptoOperationHelper.Callback<BenchmarkInputParcel, BenchmarkResult> callback
+ = new CryptoOperationHelper.Callback<BenchmarkInputParcel, BenchmarkResult>() {
+
+ @Override
+ public BenchmarkInputParcel createOperationInput() {
+ return new BenchmarkInputParcel(); // we want to perform a full consolidate
+ }
+
+ @Override
+ public void onCryptoOperationSuccess(BenchmarkResult result) {
+ result.createNotify(getActivity()).show();
+ }
+
+ @Override
+ public void onCryptoOperationCancelled() {
+
+ }
+
+ @Override
+ public void onCryptoOperationError(BenchmarkResult result) {
+ result.createNotify(getActivity()).show();
+ }
+
+ @Override
+ public boolean onCryptoSetProgress(String msg, int progress, int max) {
+ return false;
+ }
+ };
+
+ CryptoOperationHelper opHelper =
+ new CryptoOperationHelper<>(2, this, callback, R.string.progress_importing);
+
+ opHelper.cryptoOperation();
+ }
+
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (mImportOpHelper != null) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
index 43c8d2643..411dac3ef 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
@@ -43,7 +43,8 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogLevel;
import org.sufficientlysecure.keychain.operations.results.OperationResult.SubLogEntryParcel;
-import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
+import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
+import org.sufficientlysecure.keychain.ui.dialog.ShareLogDialogFragment;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
@@ -139,7 +140,7 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
// if there is no log temp file yet, create one
if (mLogTempFile == null) {
- mLogTempFile = TemporaryStorageProvider.createFile(getActivity(), "openkeychain_log.txt", "text/plain");
+ mLogTempFile = TemporaryFileProvider.createFile(getActivity(), "openkeychain_log.txt", "text/plain");
try {
OutputStream outputStream = activity.getContentResolver().openOutputStream(mLogTempFile);
outputStream.write(log.getBytes());
@@ -149,11 +150,9 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
}
}
- Intent intent = new Intent(Intent.ACTION_SEND);
- intent.putExtra(Intent.EXTRA_STREAM, mLogTempFile);
- intent.setType("text/plain");
- intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- startActivity(intent);
+
+ ShareLogDialogFragment shareLogDialog = ShareLogDialogFragment.newInstance(mLogTempFile);
+ shareLogDialog.show(getActivity().getSupportFragmentManager(), "shareLogDialog");
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java
index 6f5d98afd..7bd7bafcc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2012-2015 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
* Copyright (C) 2015 Kai Jiang <jiangkai@gmail.com>
*
@@ -27,13 +27,13 @@ import android.support.v4.app.FragmentManager.OnBackStackChangedListener;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.widget.Toolbar;
import android.view.View;
-import android.widget.AdapterView;
import com.mikepenz.community_material_typeface_library.CommunityMaterial;
+import com.mikepenz.fontawesome_typeface_library.FontAwesome;
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
-import com.mikepenz.iconics.typeface.FontAwesome;
import com.mikepenz.materialdrawer.Drawer;
import com.mikepenz.materialdrawer.DrawerBuilder;
+import com.mikepenz.materialdrawer.model.DividerDrawerItem;
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
@@ -75,25 +75,23 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
.withToolbar(mToolbar)
.addDrawerItems(
new PrimaryDrawerItem().withName(R.string.nav_keys).withIcon(CommunityMaterial.Icon.cmd_key)
- .withIdentifier(ID_KEYS).withCheckable(false),
+ .withIdentifier(ID_KEYS).withSelectable(false),
new PrimaryDrawerItem().withName(R.string.nav_encrypt_decrypt).withIcon(FontAwesome.Icon.faw_lock)
- .withIdentifier(ID_ENCRYPT_DECRYPT).withCheckable(false),
+ .withIdentifier(ID_ENCRYPT_DECRYPT).withSelectable(false),
new PrimaryDrawerItem().withName(R.string.title_api_registered_apps).withIcon(CommunityMaterial.Icon.cmd_apps)
- .withIdentifier(ID_APPS).withCheckable(false),
+ .withIdentifier(ID_APPS).withSelectable(false),
new PrimaryDrawerItem().withName(R.string.nav_backup).withIcon(CommunityMaterial.Icon.cmd_backup_restore)
- .withIdentifier(ID_BACKUP).withCheckable(false)
- )
- .addStickyDrawerItems(
- // display and stick on bottom of drawer
- new PrimaryDrawerItem().withName(R.string.menu_preferences).withIcon(GoogleMaterial.Icon.gmd_settings).withIdentifier(ID_SETTINGS).withCheckable(false),
- new PrimaryDrawerItem().withName(R.string.menu_help).withIcon(CommunityMaterial.Icon.cmd_help_circle).withIdentifier(ID_HELP).withCheckable(false)
+ .withIdentifier(ID_BACKUP).withSelectable(false),
+ new DividerDrawerItem(),
+ new PrimaryDrawerItem().withName(R.string.menu_preferences).withIcon(GoogleMaterial.Icon.gmd_settings).withIdentifier(ID_SETTINGS).withSelectable(false),
+ new PrimaryDrawerItem().withName(R.string.menu_help).withIcon(CommunityMaterial.Icon.cmd_help_circle).withIdentifier(ID_HELP).withSelectable(false)
)
.withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
@Override
- public boolean onItemClick(AdapterView<?> parent, View view, int position, long id, IDrawerItem drawerItem) {
+ public boolean onItemClick(View view, int position, IDrawerItem drawerItem) {
if (drawerItem != null) {
Intent intent = null;
- switch(drawerItem.getIdentifier()) {
+ switch (drawerItem.getIdentifier()) {
case ID_KEYS:
onKeysSelected();
break;
@@ -182,29 +180,29 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
private void onKeysSelected() {
mToolbar.setTitle(R.string.app_name);
- mDrawer.setSelectionByIdentifier(ID_KEYS, false);
+ mDrawer.setSelection(ID_KEYS, false);
Fragment frag = new KeyListFragment();
setFragment(frag, false);
}
private void onEnDecryptSelected() {
mToolbar.setTitle(R.string.nav_encrypt_decrypt);
- mDrawer.setSelectionByIdentifier(ID_ENCRYPT_DECRYPT, false);
- Fragment frag = new EncryptDecryptOverviewFragment();
+ mDrawer.setSelection(ID_ENCRYPT_DECRYPT, false);
+ Fragment frag = new EncryptDecryptFragment();
setFragment(frag, true);
}
private void onAppsSelected() {
mToolbar.setTitle(R.string.nav_apps);
- mDrawer.setSelectionByIdentifier(ID_APPS, false);
+ mDrawer.setSelection(ID_APPS, false);
Fragment frag = new AppsListFragment();
setFragment(frag, true);
}
private void onBackupSelected() {
mToolbar.setTitle(R.string.nav_backup);
- mDrawer.setSelectionByIdentifier(ID_APPS, false);
- Fragment frag = new BackupFragment();
+ mDrawer.setSelection(ID_BACKUP, false);
+ Fragment frag = new BackupRestoreFragment();
setFragment(frag, true);
}
@@ -258,16 +256,16 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
// make sure the selected icon is the one shown at this point
if (frag instanceof KeyListFragment) {
mToolbar.setTitle(R.string.app_name);
- mDrawer.setSelection(mDrawer.getPositionFromIdentifier(ID_KEYS), false);
- } else if (frag instanceof EncryptDecryptOverviewFragment) {
+ mDrawer.setSelection(mDrawer.getPosition(ID_KEYS), false);
+ } else if (frag instanceof EncryptDecryptFragment) {
mToolbar.setTitle(R.string.nav_encrypt_decrypt);
- mDrawer.setSelection(mDrawer.getPositionFromIdentifier(ID_ENCRYPT_DECRYPT), false);
+ mDrawer.setSelection(mDrawer.getPosition(ID_ENCRYPT_DECRYPT), false);
} else if (frag instanceof AppsListFragment) {
mToolbar.setTitle(R.string.nav_apps);
- mDrawer.setSelection(mDrawer.getPositionFromIdentifier(ID_APPS), false);
- } else if (frag instanceof BackupFragment) {
+ mDrawer.setSelection(mDrawer.getPosition(ID_APPS), false);
+ } else if (frag instanceof BackupRestoreFragment) {
mToolbar.setTitle(R.string.nav_backup);
- mDrawer.setSelection(mDrawer.getPositionFromIdentifier(ID_BACKUP), false);
+ mDrawer.setSelection(mDrawer.getPosition(ID_BACKUP), false);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java
index b811b218e..86b0a36d0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java
@@ -27,6 +27,7 @@ import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
+import android.widget.Toast;
import android.widget.ViewAnimator;
import org.sufficientlysecure.keychain.Constants;
@@ -72,7 +73,7 @@ public class NfcOperationActivity extends BaseNfcActivity {
private RequiredInputParcel mRequiredInput;
private Intent mServiceIntent;
- private static final byte[] BLANK_FINGERPRINT = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+ private static final byte[] BLANK_FINGERPRINT = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
private CryptoInputParcel mInputParcel;
@@ -91,7 +92,9 @@ public class NfcOperationActivity extends BaseNfcActivity {
// prevent annoying orientation changes while fumbling with the device
OrientationUtils.lockOrientation(this);
-
+ // prevent close when touching outside of the dialog (happens easily when fumbling with the device)
+ setFinishOnTouchOutside(false);
+ // keep screen on
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
mInputParcel = getIntent().getParcelableExtra(EXTRA_CRYPTO_INPUT);
@@ -107,13 +110,18 @@ public class NfcOperationActivity extends BaseNfcActivity {
public void onClick(View v) {
resumeTagHandling();
- // obtain passphrase for this subkey
- if (mRequiredInput.mType != RequiredInputParcel.RequiredInputType.NFC_MOVE_KEY_TO_CARD) {
- obtainYubiKeyPin(mRequiredInput);
- }
+ obtainPassphraseIfRequired();
vAnimator.setDisplayedChild(0);
}
});
+ Button vCancel = (Button) findViewById(R.id.nfc_activity_0_cancel);
+ vCancel.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ });
Intent intent = getIntent();
Bundle data = intent.getExtras();
@@ -121,8 +129,13 @@ public class NfcOperationActivity extends BaseNfcActivity {
mRequiredInput = data.getParcelable(EXTRA_REQUIRED_INPUT);
mServiceIntent = data.getParcelable(EXTRA_SERVICE_INTENT);
+ obtainPassphraseIfRequired();
+ }
+
+ private void obtainPassphraseIfRequired() {
// obtain passphrase for this subkey
- if (mRequiredInput.mType != RequiredInputParcel.RequiredInputType.NFC_MOVE_KEY_TO_CARD) {
+ if (mRequiredInput.mType != RequiredInputParcel.RequiredInputType.NFC_MOVE_KEY_TO_CARD
+ && mRequiredInput.mType != RequiredInputParcel.RequiredInputType.NFC_RESET_CARD) {
obtainYubiKeyPin(mRequiredInput);
}
}
@@ -237,6 +250,11 @@ public class NfcOperationActivity extends BaseNfcActivity {
break;
}
+ case NFC_RESET_CARD: {
+ nfcResetCard();
+
+ break;
+ }
default: {
throw new AssertionError("Unhandled mRequiredInput.mType");
}
@@ -245,7 +263,7 @@ public class NfcOperationActivity extends BaseNfcActivity {
}
@Override
- protected void onNfcPostExecute() throws IOException {
+ protected void onNfcPostExecute() {
if (mServiceIntent != null) {
// if we're triggered by OpenPgpService
// save updated cryptoInputParcel in cache
@@ -276,6 +294,7 @@ public class NfcOperationActivity extends BaseNfcActivity {
}
}
}
+
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
@@ -292,11 +311,27 @@ public class NfcOperationActivity extends BaseNfcActivity {
vAnimator.setDisplayedChild(3);
}
+ @Override
+ public void onNfcPinError(String error) {
+ onNfcError(error);
+
+ // clear (invalid) passphrase
+ PassphraseCacheService.clearCachedPassphrase(
+ this, mRequiredInput.getMasterKeyId(), mRequiredInput.getSubKeyId());
+ }
+
private boolean shouldPutKey(byte[] fingerprint, int idx) throws IOException {
- byte[] cardFingerprint = nfcGetFingerprint(idx);
+ byte[] cardFingerprint = nfcGetMasterKeyFingerprint(idx);
+
+ // Note: special case: This should not happen, but happens with
+ // https://github.com/FluffyKaon/OpenPGP-Card, thus for now assume true
+ if (cardFingerprint == null) {
+ return true;
+ }
+
// Slot is empty, or contains this key already. PUT KEY operation is safe
if (Arrays.equals(cardFingerprint, BLANK_FINGERPRINT) ||
- Arrays.equals(cardFingerprint, fingerprint)) {
+ Arrays.equals(cardFingerprint, fingerprint)) {
return true;
}
@@ -304,21 +339,4 @@ public class NfcOperationActivity extends BaseNfcActivity {
return false;
}
- @Override
- public void handlePinError() {
-
- // avoid a loop
- Preferences prefs = Preferences.getPreferences(this);
- if (prefs.useDefaultYubiKeyPin()) {
- toast(getString(R.string.error_pin_nodefault));
- setResult(RESULT_CANCELED);
- finish();
- return;
- }
-
- // clear (invalid) passphrase
- PassphraseCacheService.clearCachedPassphrase(
- this, mRequiredInput.getMasterKeyId(), mRequiredInput.getSubKeyId());
- }
-
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java
index e71349880..c3a33fc92 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java
@@ -29,7 +29,9 @@ import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
+import android.text.Editable;
import android.text.InputType;
+import android.text.TextWatcher;
import android.text.method.PasswordTransformationMethod;
import android.view.ContextThemeWrapper;
import android.view.KeyEvent;
@@ -117,6 +119,10 @@ public class PassphraseDialogActivity extends FragmentActivity {
mSubKeyId = Constants.key.symmetric;
break;
}
+ case BACKUP_CODE: {
+ mSubKeyId = Constants.key.backup_code;
+ break;
+ }
case PASSPHRASE: {
// handle empty passphrases by directly returning an empty crypto input parcel
@@ -186,6 +192,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
private EditText mPassphraseEditText;
private TextView mPassphraseText;
private View mInput, mProgress;
+ private EditText[] mBackupCodeEditText;
private CanonicalizedSecretKeyRing mSecretRing = null;
private boolean mIsCancelled = false;
@@ -208,6 +215,24 @@ public class PassphraseDialogActivity extends FragmentActivity {
// No title, see http://www.google.com/design/spec/components/dialogs.html#dialogs-alerts
//alert.setTitle()
+ if (mSubKeyId == Constants.key.backup_code) {
+ LayoutInflater inflater = LayoutInflater.from(theme);
+ View view = inflater.inflate(R.layout.passphrase_dialog_backup_code, null);
+ alert.setView(view);
+
+ mBackupCodeEditText = new EditText[4];
+ mBackupCodeEditText[0] = (EditText) view.findViewById(R.id.backup_code_1);
+ mBackupCodeEditText[1] = (EditText) view.findViewById(R.id.backup_code_2);
+ mBackupCodeEditText[2] = (EditText) view.findViewById(R.id.backup_code_3);
+ mBackupCodeEditText[3] = (EditText) view.findViewById(R.id.backup_code_4);
+ setupEditTextFocusNext(mBackupCodeEditText);
+
+ AlertDialog dialog = alert.create();
+ dialog.setButton(DialogInterface.BUTTON_POSITIVE,
+ activity.getString(R.string.btn_unlock), (DialogInterface.OnClickListener) null);
+ return dialog;
+ }
+
LayoutInflater inflater = LayoutInflater.from(theme);
View view = inflater.inflate(R.layout.passphrase_dialog, null);
alert.setView(view);
@@ -229,8 +254,10 @@ public class PassphraseDialogActivity extends FragmentActivity {
CanonicalizedSecretKey.SecretKeyType keyType = CanonicalizedSecretKey.SecretKeyType.PASSPHRASE;
String message;
+ String hint;
if (mSubKeyId == Constants.key.symmetric || mSubKeyId == Constants.key.none) {
message = getString(R.string.passphrase_for_symmetric_encryption);
+ hint = getString(R.string.label_passphrase);
} else {
try {
ProviderHelper helper = new ProviderHelper(activity);
@@ -255,12 +282,15 @@ public class PassphraseDialogActivity extends FragmentActivity {
switch (keyType) {
case PASSPHRASE:
message = getString(R.string.passphrase_for, userId);
+ hint = getString(R.string.label_passphrase);
break;
case PIN:
message = getString(R.string.pin_for, userId);
+ hint = getString(R.string.label_pin);
break;
case DIVERT_TO_CARD:
message = getString(R.string.yubikey_pin_for, userId);
+ hint = getString(R.string.label_pin);
break;
// special case: empty passphrase just returns the empty passphrase
case PASSPHRASE_EMPTY:
@@ -283,6 +313,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
}
mPassphraseText.setText(message);
+ mPassphraseEditText.setHint(hint);
// Hack to open keyboard.
// This is the only method that I found to work across all Android versions
@@ -327,6 +358,34 @@ public class PassphraseDialogActivity extends FragmentActivity {
return dialog;
}
+ private static void setupEditTextFocusNext(final EditText[] backupCodes) {
+ for (int i = 0; i < backupCodes.length - 1; i++) {
+
+ final int next = i + 1;
+
+ backupCodes[i].addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ boolean inserting = before < count;
+ boolean cursorAtEnd = (start + count) == 6;
+
+ if (inserting && cursorAtEnd) {
+ backupCodes[next].requestFocus();
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ }
+ });
+
+ }
+ }
+
@Override
public void onStart() {
super.onStart();
@@ -336,7 +395,23 @@ public class PassphraseDialogActivity extends FragmentActivity {
positive.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- final Passphrase passphrase = new Passphrase(mPassphraseEditText);
+
+ final Passphrase passphrase;
+ if (mSubKeyId == Constants.key.backup_code) {
+ StringBuilder backupCodeInput = new StringBuilder(26);
+ for (EditText editText : mBackupCodeEditText) {
+ if (editText.getText().length() < 6) {
+ return;
+ }
+ backupCodeInput.append(editText.getText());
+ backupCodeInput.append('-');
+ }
+ backupCodeInput.deleteCharAt(backupCodeInput.length() - 1);
+
+ passphrase = new Passphrase(backupCodeInput.toString());
+ } else {
+ passphrase = new Passphrase(mPassphraseEditText);
+ }
CryptoInputParcel cryptoInputParcel =
((PassphraseDialogActivity) getActivity()).mCryptoInputParcel;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeCaptureActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeCaptureActivity.java
new file mode 100644
index 000000000..b5d3948be
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeCaptureActivity.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.content.ContextCompat;
+import android.view.KeyEvent;
+
+import com.journeyapps.barcodescanner.CaptureManager;
+import com.journeyapps.barcodescanner.CompoundBarcodeView;
+
+import org.sufficientlysecure.keychain.R;
+
+public class QrCodeCaptureActivity extends FragmentActivity {
+ private CaptureManager capture;
+ private CompoundBarcodeView barcodeScannerView;
+
+ public static final int MY_PERMISSIONS_REQUEST_CAMERA = 42;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.qr_code_capture_activity);
+
+ barcodeScannerView = (CompoundBarcodeView) findViewById(R.id.zxing_barcode_scanner);
+ barcodeScannerView.setStatusText(getString(R.string.import_qr_code_text));
+
+ if (savedInstanceState != null) {
+ init(barcodeScannerView, getIntent(), savedInstanceState);
+ }
+
+ // check Android 6 permission
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
+ == PackageManager.PERMISSION_GRANTED) {
+ init(barcodeScannerView, getIntent(), null);
+ } else {
+ ActivityCompat.requestPermissions(this,
+ new String[]{Manifest.permission.CAMERA},
+ MY_PERMISSIONS_REQUEST_CAMERA);
+ }
+ }
+
+ private void init(CompoundBarcodeView barcodeScannerView, Intent intent, Bundle savedInstanceState) {
+ capture = new CaptureManager(this, barcodeScannerView);
+ capture.initializeFromIntent(intent, savedInstanceState);
+ capture.decode();
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[],
+ @NonNull int[] grantResults) {
+ switch (requestCode) {
+ case MY_PERMISSIONS_REQUEST_CAMERA: {
+ if (grantResults.length > 0
+ && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ // permission was granted
+ init(barcodeScannerView, getIntent(), null);
+ } else {
+ setResult(Activity.RESULT_CANCELED);
+ finish();
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (capture != null) {
+ capture.onResume();
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (capture != null) {
+ capture.onPause();
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (capture != null) {
+ capture.onDestroy();
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (capture != null) {
+ capture.onSaveInstanceState(outState);
+ }
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ return barcodeScannerView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
+ }
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
index eb9ee05af..f5c239558 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
@@ -54,14 +54,8 @@ import java.util.List;
public class SettingsActivity extends AppCompatPreferenceActivity {
- public static final String ACTION_PREFS_CLOUD = "org.sufficientlysecure.keychain.ui.PREFS_CLOUD";
- public static final String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV";
- public static final String ACTION_PREFS_PROXY = "org.sufficientlysecure.keychain.ui.PREFS_PROXY";
- public static final String ACTION_PREFS_GUI = "org.sufficientlysecure.keychain.ui.PREFS_GUI";
-
public static final int REQUEST_CODE_KEYSERVER_PREF = 0x00007005;
- private PreferenceScreen mKeyServerPreference = null;
private static Preferences sPreferences;
private ThemeChanger mThemeChanger;
@@ -74,52 +68,6 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
super.onCreate(savedInstanceState);
setupToolbar();
-
- String action = getIntent().getAction();
-
- if (ACTION_PREFS_CLOUD.equals(action)) {
- addPreferencesFromResource(R.xml.cloud_search_prefs);
-
- mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS);
- mKeyServerPreference.setSummary(keyserverSummary(this));
- mKeyServerPreference
- .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- public boolean onPreferenceClick(Preference preference) {
- Intent intent = new Intent(SettingsActivity.this,
- SettingsKeyServerActivity.class);
- intent.putExtra(SettingsKeyServerActivity.EXTRA_KEY_SERVERS,
- sPreferences.getKeyServers());
- startActivityForResult(intent, REQUEST_CODE_KEYSERVER_PREF);
- return false;
- }
- });
- initializeSearchKeyserver(
- (SwitchPreference) findPreference(Constants.Pref.SEARCH_KEYSERVER)
- );
- initializeSearchKeybase(
- (SwitchPreference) findPreference(Constants.Pref.SEARCH_KEYBASE)
- );
-
- } else if (ACTION_PREFS_ADV.equals(action)) {
- addPreferencesFromResource(R.xml.passphrase_preferences);
-
- initializePassphraseCacheSubs(
- (CheckBoxPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_SUBS));
-
- initializePassphraseCacheTtl(
- (IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL));
-
- initializeUseDefaultYubiKeyPin(
- (CheckBoxPreference) findPreference(Constants.Pref.USE_DEFAULT_YUBIKEY_PIN));
-
- initializeUseNumKeypadForYubiKeyPin(
- (CheckBoxPreference) findPreference(Constants.Pref.USE_NUMKEYPAD_FOR_YUBIKEY_PIN));
-
- } else if (ACTION_PREFS_GUI.equals(action)) {
- addPreferencesFromResource(R.xml.gui_preferences);
-
- initializeTheme((ListPreference) findPreference(Constants.Pref.THEME));
- }
}
@Override
@@ -237,9 +185,6 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
initializePassphraseCacheTtl(
(IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL));
- initializeUseDefaultYubiKeyPin(
- (CheckBoxPreference) findPreference(Constants.Pref.USE_DEFAULT_YUBIKEY_PIN));
-
initializeUseNumKeypadForYubiKeyPin(
(CheckBoxPreference) findPreference(Constants.Pref.USE_NUMKEYPAD_FOR_YUBIKEY_PIN));
}
@@ -454,23 +399,6 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
}
/**
- * This fragment shows gui preferences.
- */
- public static class GuiPrefsFragment extends PreferenceFragment {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
-
- // Load the preferences from an XML resource
- addPreferencesFromResource(R.xml.gui_preferences);
-
- initializeTheme((ListPreference) findPreference(Constants.Pref.THEME));
- }
- }
-
- /**
* This fragment shows the keyserver/contacts sync preferences
*/
public static class SyncPrefsFragment extends PreferenceFragment {
@@ -582,7 +510,6 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
return PassphrasePrefsFragment.class.getName().equals(fragmentName)
|| CloudSearchPrefsFragment.class.getName().equals(fragmentName)
|| ProxyPrefsFragment.class.getName().equals(fragmentName)
- || GuiPrefsFragment.class.getName().equals(fragmentName)
|| SyncPrefsFragment.class.getName().equals(fragmentName)
|| ExperimentalPrefsFragment.class.getName().equals(fragmentName)
|| super.isValidFragment(fragmentName);
@@ -665,17 +592,6 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
.getPreferredKeyserver();
}
- private static void initializeUseDefaultYubiKeyPin(final CheckBoxPreference mUseDefaultYubiKeyPin) {
- mUseDefaultYubiKeyPin.setChecked(sPreferences.useDefaultYubiKeyPin());
- mUseDefaultYubiKeyPin.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- mUseDefaultYubiKeyPin.setChecked((Boolean) newValue);
- sPreferences.setUseDefaultYubiKeyPin((Boolean) newValue);
- return false;
- }
- });
- }
-
private static void initializeUseNumKeypadForYubiKeyPin(final CheckBoxPreference mUseNumKeypadForYubiKeyPin) {
mUseNumKeypadForYubiKeyPin.setChecked(sPreferences.useNumKeypadForYubiKeyPin());
mUseNumKeypadForYubiKeyPin.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java
index d8edbe4f8..5a8ab36bc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java
@@ -155,7 +155,7 @@ public class SettingsKeyserverFragment extends Fragment implements RecyclerItemC
data.getBoolean(AddEditKeyserverDialogFragment.MESSAGE_VERIFIED);
if (verified) {
Notify.create(getActivity(),
- R.string.add_keyserver_verified, Notify.Style.OK).show();
+ R.string.add_keyserver_connection_verified, Notify.Style.OK).show();
} else {
Notify.create(getActivity(),
R.string.add_keyserver_without_verification,
@@ -177,26 +177,6 @@ public class SettingsKeyserverFragment extends Fragment implements RecyclerItemC
}
break;
}
- case AddEditKeyserverDialogFragment.MESSAGE_VERIFICATION_FAILED: {
- AddEditKeyserverDialogFragment.FailureReason failureReason =
- (AddEditKeyserverDialogFragment.FailureReason) data.getSerializable(
- AddEditKeyserverDialogFragment.MESSAGE_FAILURE_REASON);
- switch (failureReason) {
- case CONNECTION_FAILED: {
- Notify.create(getActivity(),
- R.string.add_keyserver_connection_failed,
- Notify.Style.ERROR).show();
- break;
- }
- case INVALID_URL: {
- Notify.create(getActivity(),
- R.string.add_keyserver_invalid_url,
- Notify.Style.ERROR).show();
- break;
- }
- }
- break;
- }
}
}
};
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
index 0415128a2..f38e4928d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java
@@ -17,6 +17,7 @@
package org.sufficientlysecure.keychain.ui;
+
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@@ -29,10 +30,12 @@ import android.widget.Spinner;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.operations.results.ExportResult;
+import org.sufficientlysecure.keychain.operations.results.UploadResult;
+import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.service.ExportKeyringParcel;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.UploadKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.util.Log;
@@ -42,7 +45,7 @@ import org.sufficientlysecure.keychain.util.Preferences;
* Sends the selected public key to a keyserver
*/
public class UploadKeyActivity extends BaseActivity
- implements CryptoOperationHelper.Callback<ExportKeyringParcel, ExportResult> {
+ implements CryptoOperationHelper.Callback<UploadKeyringParcel, UploadResult> {
private View mUploadButton;
private Spinner mKeyServerSpinner;
@@ -50,8 +53,8 @@ public class UploadKeyActivity extends BaseActivity
// CryptoOperationHelper.Callback vars
private String mKeyserver;
- private Uri mUnifiedKeyringUri;
- private CryptoOperationHelper<ExportKeyringParcel, ExportResult> mUploadOpHelper;
+ private long mMasterKeyId;
+ private CryptoOperationHelper<UploadKeyringParcel, UploadResult> mUploadOpHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -85,6 +88,16 @@ public class UploadKeyActivity extends BaseActivity
finish();
return;
}
+
+ try {
+ mMasterKeyId = new ProviderHelper(this).getCachedPublicKeyRing(
+ KeyRings.buildUnifiedKeyRingUri(mDataUri)).getMasterKeyId();
+ } catch (PgpKeyNotFoundException e) {
+ Log.e(Constants.TAG, "Intent data pointed to bad key!");
+ finish();
+ return;
+ }
+
}
@Override
@@ -101,13 +114,10 @@ public class UploadKeyActivity extends BaseActivity
}
private void uploadKey() {
- Uri blobUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
- mUnifiedKeyringUri = blobUri;
-
String server = (String) mKeyServerSpinner.getSelectedItem();
mKeyserver = server;
- mUploadOpHelper = new CryptoOperationHelper(1, this, this, R.string.progress_uploading);
+ mUploadOpHelper = new CryptoOperationHelper<>(1, this, this, R.string.progress_uploading);
mUploadOpHelper.cryptoOperation();
}
@@ -125,12 +135,12 @@ public class UploadKeyActivity extends BaseActivity
}
@Override
- public ExportKeyringParcel createOperationInput() {
- return new ExportKeyringParcel(mKeyserver, mUnifiedKeyringUri);
+ public UploadKeyringParcel createOperationInput() {
+ return new UploadKeyringParcel(mKeyserver, mMasterKeyId);
}
@Override
- public void onCryptoOperationSuccess(ExportResult result) {
+ public void onCryptoOperationSuccess(UploadResult result) {
result.createNotify(this).show();
}
@@ -140,7 +150,7 @@ public class UploadKeyActivity extends BaseActivity
}
@Override
- public void onCryptoOperationError(ExportResult result) {
+ public void onCryptoOperationError(UploadResult result) {
result.createNotify(this).show();
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index a09e74abe..0f538cd1b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -19,7 +19,6 @@
package org.sufficientlysecure.keychain.ui;
-import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -39,6 +38,7 @@ import android.os.Handler;
import android.provider.ContactsContract;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
+import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentManager;
@@ -65,12 +65,14 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.ViewKeyFragment.PostponeType;
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
@@ -85,7 +87,6 @@ import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;
import org.sufficientlysecure.keychain.util.ContactHelper;
-import org.sufficientlysecure.keychain.util.ExportHelper;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.NfcHelper;
import org.sufficientlysecure.keychain.util.Preferences;
@@ -355,7 +356,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
startActivity(homeIntent);
return true;
}
- case R.id.menu_key_view_export_file: {
+ case R.id.menu_key_view_backup: {
startPassphraseActivity(REQUEST_BACKUP);
return true;
}
@@ -405,8 +406,8 @@ public class ViewKeyActivity extends BaseNfcActivity implements
MenuItem editKey = menu.findItem(R.id.menu_key_view_edit);
editKey.setVisible(mIsSecret);
- MenuItem exportKey = menu.findItem(R.id.menu_key_view_export_file);
- exportKey.setVisible(mIsSecret);
+ MenuItem backupKey = menu.findItem(R.id.menu_key_view_backup);
+ backupKey.setVisible(mIsSecret);
MenuItem addLinked = menu.findItem(R.id.menu_key_view_add_linked_identity);
addLinked.setVisible(mIsSecret
@@ -460,15 +461,40 @@ public class ViewKeyActivity extends BaseNfcActivity implements
}
private void startPassphraseActivity(int requestCode) {
- Intent intent = new Intent(this, PassphraseDialogActivity.class);
- intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, mMasterKeyId);
- startActivityForResult(intent, requestCode);
+
+ if (keyHasPassphrase()) {
+ Intent intent = new Intent(this, PassphraseDialogActivity.class);
+ intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, mMasterKeyId);
+ startActivityForResult(intent, requestCode);
+ } else {
+ startBackupActivity();
+ }
+ }
+
+ private boolean keyHasPassphrase() {
+ try {
+ SecretKeyType secretKeyType =
+ mProviderHelper.getCachedPublicKeyRing(mMasterKeyId).getSecretKeyType(mMasterKeyId);
+ switch (secretKeyType) {
+ // all of these make no sense to ask
+ case PASSPHRASE_EMPTY:
+ case GNU_DUMMY:
+ case DIVERT_TO_CARD:
+ case UNAVAILABLE:
+ return false;
+ default:
+ return true;
+ }
+ } catch (NotFoundException e) {
+ return false;
+ }
}
- private void backupToFile() {
- new ExportHelper(this).showExportKeysDialog(
- mMasterKeyId, new File(Constants.Path.APP_DIR,
- KeyFormattingUtils.convertKeyIdToHex(mMasterKeyId) + ".sec.asc"), true);
+ private void startBackupActivity() {
+ Intent intent = new Intent(this, BackupActivity.class);
+ intent.putExtra(BackupActivity.EXTRA_MASTER_KEY_IDS, new long[] { mMasterKeyId });
+ intent.putExtra(BackupActivity.EXTRA_SECRET, true);
+ startActivity(intent);
}
private void deleteKey() {
@@ -524,7 +550,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
return;
}
- backupToFile();
+ startBackupActivity();
return;
}
@@ -564,7 +590,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
}
@Override
- protected void onNfcPostExecute() throws IOException {
+ protected void onNfcPostExecute() {
long yubiKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mNfcFingerprints);
@@ -854,7 +880,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
mActionEncryptFile.setVisibility(View.INVISIBLE);
mActionEncryptText.setVisibility(View.INVISIBLE);
mActionNfc.setVisibility(View.INVISIBLE);
- mFab.setVisibility(View.GONE);
+ hideFab();
mQrCodeLayout.setVisibility(View.GONE);
} else if (mIsExpired) {
if (mIsSecret) {
@@ -870,7 +896,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
mActionEncryptFile.setVisibility(View.INVISIBLE);
mActionEncryptText.setVisibility(View.INVISIBLE);
mActionNfc.setVisibility(View.INVISIBLE);
- mFab.setVisibility(View.GONE);
+ hideFab();
mQrCodeLayout.setVisibility(View.GONE);
} else if (mIsSecret) {
mStatusText.setText(R.string.view_key_my_key);
@@ -912,7 +938,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
} else {
mActionNfc.setVisibility(View.GONE);
}
- mFab.setVisibility(View.VISIBLE);
+ showFab();
// noinspection deprecation (no getDrawable with theme at current minApi level 15!)
mFab.setImageDrawable(getResources().getDrawable(R.drawable.ic_repeat_white_24dp));
} else {
@@ -929,7 +955,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
color = getResources().getColor(R.color.key_flag_green);
photoTask.execute(mMasterKeyId);
- mFab.setVisibility(View.GONE);
+ hideFab();
} else {
mStatusText.setText(R.string.view_key_unverified);
mStatusImage.setVisibility(View.VISIBLE);
@@ -937,7 +963,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements
State.UNVERIFIED, R.color.icons, true);
color = getResources().getColor(R.color.key_flag_orange);
- mFab.setVisibility(View.VISIBLE);
+ showFab();
}
}
@@ -967,6 +993,28 @@ public class ViewKeyActivity extends BaseNfcActivity implements
}
}
+ /**
+ * Helper to show Fab, from http://stackoverflow.com/a/31047038
+ */
+ private void showFab() {
+ CoordinatorLayout.LayoutParams p = (CoordinatorLayout.LayoutParams) mFab.getLayoutParams();
+ p.setBehavior(new FloatingActionButton.Behavior());
+ p.setAnchorId(R.id.app_bar_layout);
+ mFab.setLayoutParams(p);
+ mFab.setVisibility(View.VISIBLE);
+ }
+
+ /**
+ * Helper to hide Fab, from http://stackoverflow.com/a/31047038
+ */
+ private void hideFab() {
+ CoordinatorLayout.LayoutParams p = (CoordinatorLayout.LayoutParams) mFab.getLayoutParams();
+ p.setBehavior(null); //should disable default animations
+ p.setAnchorId(View.NO_ID); //should let you set visibility
+ mFab.setLayoutParams(p);
+ mFab.setVisibility(View.GONE);
+ }
+
@Override
public void onLoaderReset(Loader<Cursor> loader) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java
index edd9feec9..bba6a6dc1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java
@@ -41,13 +41,11 @@ import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter;
import org.sufficientlysecure.keychain.ui.base.BaseActivity;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.ContactHelper;
-import org.sufficientlysecure.keychain.util.ExportHelper;
import org.sufficientlysecure.keychain.util.Log;
public class ViewKeyAdvActivity extends BaseActivity implements
LoaderManager.LoaderCallbacks<Cursor> {
- ExportHelper mExportHelper;
ProviderHelper mProviderHelper;
protected Uri mDataUri;
@@ -75,7 +73,6 @@ public class ViewKeyAdvActivity extends BaseActivity implements
}
});
- mExportHelper = new ExportHelper(this);
mProviderHelper = new ProviderHelper(this);
mViewPager = (ViewPager) findViewById(R.id.pager);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
index 4a46896bc..c5e575e32 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
@@ -52,18 +52,18 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
+import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;
-import org.sufficientlysecure.keychain.util.ExportHelper;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.NfcHelper;
@@ -84,7 +84,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
private Uri mDataUri;
private byte[] mFingerprint;
- private long mMasterKeyId;
+ private String mUserId;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) {
@@ -107,7 +107,6 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
View vFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share);
View vFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard);
View vKeyShareButton = view.findViewById(R.id.view_key_action_key_share);
- View vKeySafeButton = view.findViewById(R.id.view_key_action_key_export);
View vKeyNfcButton = view.findViewById(R.id.view_key_action_key_nfc);
View vKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard);
ImageButton vKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger);
@@ -118,31 +117,25 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
vFingerprintShareButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- share(true, false);
+ shareFingerprint(false);
}
});
vFingerprintClipboardButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- share(true, true);
+ shareFingerprint(true);
}
});
vKeyShareButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- share(false, false);
- }
- });
- vKeySafeButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- exportToFile();
+ shareKey(false);
}
});
vKeyClipboardButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- share(false, true);
+ shareKey(true);
}
});
@@ -174,11 +167,6 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
return root;
}
- private void exportToFile() {
- new ExportHelper(getActivity()).showExportKeysDialog(
- mMasterKeyId, Constants.Path.APP_DIR_FILE, false);
- }
-
private void startSafeSlinger(Uri dataUri) {
long keyId = 0;
try {
@@ -193,7 +181,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
startActivityForResult(safeSlingerIntent, 0);
}
- private void share(boolean fingerprintOnly, boolean toClipboard) {
+ private void shareKey(boolean toClipboard) {
Activity activity = getActivity();
if (activity == null || mFingerprint == null) {
return;
@@ -201,18 +189,8 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
ProviderHelper providerHelper = new ProviderHelper(activity);
try {
- String content;
- if (fingerprintOnly) {
- String fingerprint = KeyFormattingUtils.convertFingerprintToHex(mFingerprint);
- if (!toClipboard) {
- content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
- } else {
- content = fingerprint;
- }
- } else {
- content = providerHelper.getKeyRingAsArmoredString(
- KeychainContract.KeyRingData.buildPublicKeyRingUri(mDataUri));
- }
+ String content = providerHelper.getKeyRingAsArmoredString(
+ KeychainContract.KeyRingData.buildPublicKeyRingUri(mDataUri));
if (toClipboard) {
ClipboardManager clipMan = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
@@ -224,29 +202,26 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
ClipData clip = ClipData.newPlainText(Constants.CLIPBOARD_LABEL, content);
clipMan.setPrimaryClip(clip);
- Notify.create(activity, fingerprintOnly ? R.string.fingerprint_copied_to_clipboard
- : R.string.key_copied_to_clipboard, Notify.Style.OK).show();
- return;
- }
-
- // Android will fail with android.os.TransactionTooLargeException if key is too big
- // see http://www.lonestarprod.com/?p=34
- if (content.length() >= 86389) {
- Notify.create(activity, R.string.key_too_big_for_sharing, Notify.Style.ERROR).show();
+ Notify.create(activity, R.string.key_copied_to_clipboard, Notify.Style.OK).show();
return;
}
// let user choose application
Intent sendIntent = new Intent(Intent.ACTION_SEND);
- sendIntent.putExtra(Intent.EXTRA_TEXT, content);
sendIntent.setType("text/plain");
- // Bluetooth Share will convert text/plain sent via EXTRA_TEXT to HTML
- // Add replacement extra to send a text/plain file instead.
+ // NOTE: Don't use Intent.EXTRA_TEXT to send the key
+ // better send it via a Uri!
+ // example: Bluetooth Share will convert text/plain sent via Intent.EXTRA_TEXT to HTML
try {
- TemporaryStorageProvider shareFileProv = new TemporaryStorageProvider();
- Uri contentUri = TemporaryStorageProvider.createFile(activity,
- KeyFormattingUtils.convertFingerprintToHex(mFingerprint) + Constants.FILE_EXTENSION_ASC);
+ TemporaryFileProvider shareFileProv = new TemporaryFileProvider();
+
+ String filename = KeyFormattingUtils.convertFingerprintToHex(mFingerprint);
+ KeyRing.UserId mainUserId = KeyRing.splitUserId(mUserId);
+ if (mainUserId.name != null) {
+ filename = mainUserId.name;
+ }
+ Uri contentUri = TemporaryFileProvider.createFile(activity, filename + Constants.FILE_EXTENSION_ASC);
BufferedWriter contentWriter = new BufferedWriter(new OutputStreamWriter(
new ParcelFileDescriptor.AutoCloseOutputStream(
@@ -256,18 +231,15 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
sendIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
} catch (FileNotFoundException e) {
- Log.e(Constants.TAG, "error creating temporary Bluetooth key share file!", e);
+ Log.e(Constants.TAG, "Error creating temporary key share file!", e);
// no need for a snackbar because one sharing option doesn't work
// Notify.create(getActivity(), R.string.error_temp_file, Notify.Style.ERROR).show();
}
-
- String title = getString(fingerprintOnly
- ? R.string.title_share_fingerprint_with : R.string.title_share_key);
+ String title = getString(R.string.title_share_key);
Intent shareChooser = Intent.createChooser(sendIntent, title);
startActivity(shareChooser);
-
} catch (PgpGeneralException | IOException e) {
Log.e(Constants.TAG, "error processing key!", e);
Notify.create(activity, R.string.error_key_processing, Notify.Style.ERROR).show();
@@ -277,6 +249,45 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
}
}
+ private void shareFingerprint(boolean toClipboard) {
+ Activity activity = getActivity();
+ if (activity == null || mFingerprint == null) {
+ return;
+ }
+
+ String content;
+ String fingerprint = KeyFormattingUtils.convertFingerprintToHex(mFingerprint);
+ if (!toClipboard) {
+ content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
+ } else {
+ content = fingerprint;
+ }
+
+ if (toClipboard) {
+ ClipboardManager clipMan = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
+ if (clipMan == null) {
+ Notify.create(activity, R.string.error_clipboard_copy, Style.ERROR);
+ return;
+ }
+
+ ClipData clip = ClipData.newPlainText(Constants.CLIPBOARD_LABEL, content);
+ clipMan.setPrimaryClip(clip);
+
+ Notify.create(activity, R.string.fingerprint_copied_to_clipboard, Notify.Style.OK).show();
+ return;
+ }
+
+ // let user choose application
+ Intent sendIntent = new Intent(Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_TEXT, content);
+ sendIntent.setType("text/plain");
+
+ String title = getString(R.string.title_share_fingerprint_with);
+ Intent shareChooser = Intent.createChooser(sendIntent, title);
+
+ startActivity(shareChooser);
+ }
+
private void showQrCodeDialog() {
Intent qrCodeIntent = new Intent(getActivity(), QrCodeViewActivity.class);
@@ -318,11 +329,12 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
mNfcHelper.initNfc(mDataUri);
}
- static final String[] UNIFIED_PROJECTION = new String[] {
- KeyRings._ID, KeyRings.FINGERPRINT
+ static final String[] UNIFIED_PROJECTION = new String[]{
+ KeyRings._ID, KeyRings.FINGERPRINT, KeyRings.USER_ID
};
static final int INDEX_UNIFIED_FINGERPRINT = 1;
+ static final int INDEX_UNIFIED_USER_ID = 2;
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
setContentShown(false);
@@ -351,6 +363,8 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT);
setFingerprint(fingerprintBlob);
+ mUserId = data.getString(INDEX_UNIFIED_USER_ID);
+
break;
}
}
@@ -367,10 +381,11 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
mFingerprint = null;
}
- /** Load QR Code asynchronously and with a fade in animation */
+ /**
+ * Load QR Code asynchronously and with a fade in animation
+ */
private void setFingerprint(byte[] fingerprintBlob) {
mFingerprint = fingerprintBlob;
- mMasterKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(fingerprintBlob);
final String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintBlob);
mFingerprintView.setText(KeyFormattingUtils.colorizeFingerprint(fingerprint));
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeybaseFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeybaseFragment.java
index 266633061..11c032517 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeybaseFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeybaseFragment.java
@@ -40,6 +40,7 @@ import android.widget.TableRow;
import android.widget.TextView;
import com.textuality.keybase.lib.KeybaseException;
+import com.textuality.keybase.lib.KeybaseQuery;
import com.textuality.keybase.lib.Proof;
import com.textuality.keybase.lib.User;
@@ -51,6 +52,7 @@ import org.sufficientlysecure.keychain.service.KeybaseVerificationParcel;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.util.OkHttpKeybaseClient;
import org.sufficientlysecure.keychain.util.ParcelableProxy;
import org.sufficientlysecure.keychain.util.Preferences;
import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
@@ -224,8 +226,9 @@ public class ViewKeyKeybaseFragment extends LoaderFragment implements
}
}
- // look for evidence from keybase in the background, make tabular version of result
- //
+ /**
+ * look for evidence from keybase in the background, make tabular version of result
+ */
private class DescribeKey extends AsyncTask<String, Void, ResultPage> {
ParcelableProxy mParcelableProxy;
@@ -240,7 +243,9 @@ public class ViewKeyKeybaseFragment extends LoaderFragment implements
final ArrayList<CharSequence> proofList = new ArrayList<CharSequence>();
final Hashtable<Integer, ArrayList<Proof>> proofs = new Hashtable<Integer, ArrayList<Proof>>();
try {
- User keybaseUser = User.findByFingerprint(fingerprint, mParcelableProxy.getProxy());
+ KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient());
+ keybaseQuery.setProxy(mParcelableProxy.getProxy());
+ User keybaseUser = User.findByFingerprint(keybaseQuery, fingerprint);
for (Proof proof : keybaseUser.getProofs()) {
Integer proofType = proof.getType();
appendIfOK(proofs, proofType, proof);
@@ -266,7 +271,12 @@ public class ViewKeyKeybaseFragment extends LoaderFragment implements
} catch (KeybaseException ignored) {
}
- return new ResultPage(getString(R.string.key_trust_results_prefix), proofList);
+ String prefix = "";
+ if (isAdded()) {
+ prefix = getString(R.string.key_trust_results_prefix);
+ }
+
+ return new ResultPage(prefix, proofList);
}
private SpannableStringBuilder formatSpannableString(SpannableStringBuilder proofLinks, String proofType) {
@@ -291,7 +301,10 @@ public class ViewKeyKeybaseFragment extends LoaderFragment implements
if (haveProofFor(proof.getType())) {
ssb.append("\u00a0[");
startAt = ssb.length();
- String verify = getString(R.string.keybase_verify);
+ String verify = "";
+ if (isAdded()) {
+ verify = getString(R.string.keybase_verify);
+ }
ssb.append(verify);
ClickableSpan clicker = new ClickableSpan() {
@Override
@@ -308,6 +321,11 @@ public class ViewKeyKeybaseFragment extends LoaderFragment implements
@Override
protected void onPostExecute(ResultPage result) {
super.onPostExecute(result);
+ // stop if fragment is no longer added to an activity
+ if(!isAdded()) {
+ return;
+ }
+
if (result.mProofs.isEmpty()) {
result.mHeader = getActivity().getString(R.string.key_trust_no_cloud_evidence);
}
@@ -356,7 +374,12 @@ public class ViewKeyKeybaseFragment extends LoaderFragment implements
default:
stringIndex = R.string.keybase_narrative_unknown;
}
- return getActivity().getString(stringIndex);
+
+ if (isAdded()) {
+ return getString(stringIndex);
+ } else {
+ return "";
+ }
}
private void appendIfOK(Hashtable<Integer, ArrayList<Proof>> table, Integer proofType, Proof proof) throws KeybaseException {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java
index 139512ba9..038ebd5dd 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java
@@ -17,6 +17,14 @@
package org.sufficientlysecure.keychain.ui.adapter;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.util.LongSparseArray;
@@ -28,28 +36,26 @@ import org.sufficientlysecure.keychain.operations.results.GetKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing.IteratorWithIOThrow;
+import org.sufficientlysecure.keychain.ui.ImportKeysListFragment.BytesLoaderState;
+import org.sufficientlysecure.keychain.util.FileHelper;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.PositionAwareInputStream;
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-
public class ImportKeysListLoader
extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
final Context mContext;
- final InputData mInputData;
+ final BytesLoaderState mLoaderState;
ArrayList<ImportKeysListEntry> mData = new ArrayList<>();
LongSparseArray<ParcelableKeyRing> mParcelableRings = new LongSparseArray<>();
AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper;
- public ImportKeysListLoader(Context context, InputData inputData) {
+ public ImportKeysListLoader(Context context, BytesLoaderState inputData) {
super(context);
this.mContext = context;
- this.mInputData = inputData;
+ this.mLoaderState = inputData;
}
@Override
@@ -62,12 +68,13 @@ public class ImportKeysListLoader
GetKeyResult getKeyResult = new GetKeyResult(GetKeyResult.RESULT_OK, null);
mEntryListWrapper = new AsyncTaskResultWrapper<>(mData, getKeyResult);
- if (mInputData == null) {
+ if (mLoaderState == null) {
Log.e(Constants.TAG, "Input data is null!");
return mEntryListWrapper;
}
- generateListOfKeyrings(mInputData);
+ InputData inputData = getInputData(getContext(), mLoaderState);
+ generateListOfKeyrings(inputData);
return mEntryListWrapper;
}
@@ -99,12 +106,7 @@ public class ImportKeysListLoader
return mParcelableRings;
}
- /**
- * Reads all PGPKeyRing objects from input
- *
- * @param inputData
- * @return
- */
+ /** Reads all PGPKeyRing objects from the bytes of an InputData object. */
private void generateListOfKeyrings(InputData inputData) {
PositionAwareInputStream progressIn = new PositionAwareInputStream(
inputData.getInputStream());
@@ -132,4 +134,23 @@ public class ImportKeysListLoader
}
}
+ private static InputData getInputData(Context context, BytesLoaderState loaderState) {
+ InputData inputData = null;
+ if (loaderState.mKeyBytes != null) {
+ inputData = new InputData(new ByteArrayInputStream(loaderState.mKeyBytes), loaderState.mKeyBytes.length);
+ } else if (loaderState.mDataUri != null) {
+ try {
+ InputStream inputStream = context.getContentResolver().openInputStream(loaderState.mDataUri);
+ long length = FileHelper.getFileSize(context, loaderState.mDataUri, -1);
+
+ inputData = new InputData(inputStream, length);
+ } catch (FileNotFoundException e) {
+ Log.e(Constants.TAG, "FileNotFoundException!", e);
+ return null;
+ }
+ }
+
+ return inputData;
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeySelectableAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeySelectableAdapter.java
index 471a20411..7cc37b3a3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeySelectableAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeySelectableAdapter.java
@@ -1,13 +1,8 @@
package org.sufficientlysecure.keychain.ui.adapter;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
import android.content.Context;
import android.database.Cursor;
-import android.support.v7.internal.widget.AdapterViewCompat;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
@@ -18,6 +13,10 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Log;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
public class KeySelectableAdapter extends KeyAdapter implements OnItemClickListener {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java
index 5cf0e6e08..5566c725b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java
@@ -24,6 +24,7 @@ import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
+import android.os.Build.VERSION_CODES;
import android.support.v4.content.CursorLoader;
import android.util.Log;
import android.view.LayoutInflater;
@@ -228,9 +229,11 @@ public class LinkedIdsAdapter extends UserAttributesAdapter {
}
public void seekAttention() {
- ObjectAnimator anim = SubtleAttentionSeeker.tintText(vComment, 1000);
- anim.setStartDelay(200);
- anim.start();
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ ObjectAnimator anim = SubtleAttentionSeeker.tintText(vComment, 1000);
+ anim.setStartDelay(200);
+ anim.start();
+ }
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java
index 972421abe..3e0bc7890 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseNfcActivity.java
@@ -35,7 +35,6 @@ import android.nfc.TagLostException;
import android.nfc.tech.IsoDep;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.widget.Toast;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.util.Arrays;
@@ -103,7 +102,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
/**
* Override to handle result of NFC operations (UI thread)
*/
- protected void onNfcPostExecute() throws IOException {
+ protected void onNfcPostExecute() {
final long subKeyId = KeyFormattingUtils.getKeyIdFromFingerprint(mNfcFingerprints);
@@ -134,9 +133,16 @@ public abstract class BaseNfcActivity extends BaseActivity {
Notify.create(this, error, Style.WARN).show();
}
+ /**
+ * Override to do something when PIN is wrong, e.g., clear passphrases (UI thread)
+ */
+ protected void onNfcPinError(String error) {
+ onNfcError(error);
+ }
+
public void handleIntentInBackground(final Intent intent) {
// Actual NFC operations are executed in doInBackground to not block the UI thread
- new AsyncTask<Void, Void, Exception>() {
+ new AsyncTask<Void, Void, IOException>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
@@ -144,11 +150,9 @@ public abstract class BaseNfcActivity extends BaseActivity {
}
@Override
- protected Exception doInBackground(Void... params) {
+ protected IOException doInBackground(Void... params) {
try {
handleTagDiscoveredIntent(intent);
- } catch (CardException e) {
- return e;
} catch (IOException e) {
return e;
}
@@ -157,7 +161,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
}
@Override
- protected void onPostExecute(Exception exception) {
+ protected void onPostExecute(IOException exception) {
super.onPostExecute(exception);
if (exception != null) {
@@ -165,11 +169,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
return;
}
- try {
- onNfcPostExecute();
- } catch (IOException e) {
- handleNfcError(e);
- }
+ onNfcPostExecute();
}
}.execute();
}
@@ -221,24 +221,30 @@ public abstract class BaseNfcActivity extends BaseActivity {
}
}
- private void handleNfcError(Exception e) {
- Log.e(Constants.TAG, "nfc error", e);
+ private void handleNfcError(IOException e) {
if (e instanceof TagLostException) {
onNfcError(getString(R.string.error_nfc_tag_lost));
return;
}
+ if (e instanceof IsoDepNotSupportedException) {
+ onNfcError(getString(R.string.error_nfc_iso_dep_not_supported));
+ return;
+ }
+
short status;
if (e instanceof CardException) {
status = ((CardException) e).getResponseCode();
} else {
status = -1;
}
- // When entering a PIN, a status of 63CX indicates X attempts remaining.
- if ((status & (short)0xFFF0) == 0x63C0) {
+
+ // Wrong PIN, a status of 63CX indicates X attempts remaining.
+ if ((status & (short) 0xFFF0) == 0x63C0) {
int tries = status & 0x000F;
- onNfcError(getResources().getQuantityString(R.plurals.error_pin, tries, tries));
+ // hook to do something different when PIN is wrong
+ onNfcPinError(getResources().getQuantityString(R.plurals.error_pin, tries, tries));
return;
}
@@ -272,7 +278,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
break;
}
case 0x6700: {
- onNfcError(getString(R.string.error_nfc_wrong_length));
+ onNfcPinError(getString(R.string.error_nfc_wrong_length));
break;
}
case 0x6982: {
@@ -307,12 +313,6 @@ public abstract class BaseNfcActivity extends BaseActivity {
}
- public void handlePinError() {
- toast("Wrong PIN!");
- setResult(RESULT_CANCELED);
- finish();
- }
-
/**
* Called when the system is about to start resuming a previous activity,
* disables NFC Foreground Dispatch
@@ -337,18 +337,11 @@ public abstract class BaseNfcActivity extends BaseActivity {
protected void obtainYubiKeyPin(RequiredInputParcel requiredInput) {
- // shortcut if we only use the default yubikey pin
- Preferences prefs = Preferences.getPreferences(this);
- if (prefs.useDefaultYubiKeyPin()) {
- mPin = new Passphrase("123456");
- return;
- }
-
try {
- Passphrase phrase = PassphraseCacheService.getCachedPassphrase(this,
+ Passphrase passphrase = PassphraseCacheService.getCachedPassphrase(this,
requiredInput.getMasterKeyId(), requiredInput.getSubKeyId());
- if (phrase != null) {
- mPin = phrase;
+ if (passphrase != null) {
+ mPin = passphrase;
return;
}
@@ -363,10 +356,6 @@ public abstract class BaseNfcActivity extends BaseActivity {
}
- protected void setYubiKeyPin(Passphrase pin) {
- mPin = pin;
- }
-
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
@@ -406,6 +395,9 @@ public abstract class BaseNfcActivity extends BaseActivity {
// Connect to the detected tag, setting a couple of settings
mIsoDep = IsoDep.get(detectedTag);
+ if (mIsoDep == null) {
+ throw new IsoDepNotSupportedException("Tag does not support ISO-DEP (ISO 14443-4)");
+ }
mIsoDep.setTimeout(TIMEOUT); // timeout is set to 100 seconds to avoid cancellation during calculation
mIsoDep.connect();
@@ -448,7 +440,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
* @return The long key id of the requested key, or null if not found.
*/
public Long nfcGetKeyId(int idx) throws IOException {
- byte[] fp = nfcGetFingerprint(idx);
+ byte[] fp = nfcGetMasterKeyFingerprint(idx);
if (fp == null) {
return null;
}
@@ -469,7 +461,7 @@ public abstract class BaseNfcActivity extends BaseActivity {
byte[] buf = mIsoDep.transceive(Hex.decode(data));
Iso7816TLV tlv = Iso7816TLV.readSingle(buf, true);
- Log.d(Constants.TAG, "nfc tlv data:\n" + tlv.prettyPrint());
+ Log.d(Constants.TAG, "nfcGetFingerprints() Iso7816TLV tlv data:\n" + tlv.prettyPrint());
Iso7816TLV fptlv = Iso7816TLV.findRecursive(tlv, 0xc5);
if (fptlv == null) {
@@ -494,8 +486,11 @@ public abstract class BaseNfcActivity extends BaseActivity {
* @param idx Index of the key to return the fingerprint from.
* @return The fingerprint of the requested key, or null if not found.
*/
- public byte[] nfcGetFingerprint(int idx) throws IOException {
+ public byte[] nfcGetMasterKeyFingerprint(int idx) throws IOException {
byte[] data = nfcGetFingerprints();
+ if (data == null) {
+ return null;
+ }
// return the master key fingerprint
ByteBuffer fpbuf = ByteBuffer.wrap(data);
@@ -507,14 +502,11 @@ public abstract class BaseNfcActivity extends BaseActivity {
}
public byte[] nfcGetAid() throws IOException {
-
String info = "00CA004F00";
return mIsoDep.transceive(Hex.decode(info));
-
}
public String nfcGetUserId() throws IOException {
-
String info = "00CA006500";
return nfcGetHolderName(nfcCommunicate(info));
}
@@ -648,8 +640,6 @@ public abstract class BaseNfcActivity extends BaseActivity {
String decryptedSessionKey = nfcGetDataField(second);
- Log.d(Constants.TAG, "decryptedSessionKey: " + decryptedSessionKey);
-
return Hex.decode(decryptedSessionKey);
}
@@ -671,18 +661,8 @@ public abstract class BaseNfcActivity extends BaseActivity {
// SW1/2 0x9000 is the generic "ok" response, which we expect most of the time.
// See specification, page 51
String accepted = "9000";
-
- // Command APDU for VERIFY command (page 32)
- String login =
- "00" // CLA
- + "20" // INS
- + "00" // P1
- + String.format("%02x", mode) // P2
- + String.format("%02x", pin.length) // Lc
- + Hex.toHexString(pin);
- String response = nfcCommunicate(login); // login
+ String response = tryPin(mode, pin); // login
if (!response.equals(accepted)) {
- handlePinError();
throw new CardException("Bad PIN!", parseCardStatus(response));
}
@@ -696,6 +676,51 @@ public abstract class BaseNfcActivity extends BaseActivity {
}
}
+ public void nfcResetCard() throws IOException {
+ String accepted = "9000";
+
+ // try wrong PIN 4 times until counter goes to C0
+ byte[] pin = "XXXXXX".getBytes();
+ for (int i = 0; i <= 4; i++) {
+ String response = tryPin(0x81, pin);
+ if (response.equals(accepted)) { // Should NOT accept!
+ throw new CardException("Should never happen, XXXXXX has been accepted!", parseCardStatus(response));
+ }
+ }
+
+ // try wrong Admin PIN 4 times until counter goes to C0
+ byte[] adminPin = "XXXXXXXX".getBytes();
+ for (int i = 0; i <= 4; i++) {
+ String response = tryPin(0x83, adminPin);
+ if (response.equals(accepted)) { // Should NOT accept!
+ throw new CardException("Should never happen, XXXXXXXX has been accepted", parseCardStatus(response));
+ }
+ }
+
+ // reactivate card!
+ String reactivate1 = "00" + "e6" + "00" + "00";
+ String reactivate2 = "00" + "44" + "00" + "00";
+ String response1 = nfcCommunicate(reactivate1);
+ String response2 = nfcCommunicate(reactivate2);
+ if (!response1.equals(accepted) || !response2.equals(accepted)) {
+ throw new CardException("Reactivating failed!", parseCardStatus(response1));
+ }
+
+ }
+
+ private String tryPin(int mode, byte[] pin) throws IOException {
+ // Command APDU for VERIFY command (page 32)
+ String login =
+ "00" // CLA
+ + "20" // INS
+ + "00" // P1
+ + String.format("%02x", mode) // P2
+ + String.format("%02x", pin.length) // Lc
+ + Hex.toHexString(pin);
+
+ return nfcCommunicate(login);
+ }
+
/** Modifies the user's PW1 or PW3. Before sending, the new PIN will be validated for
* conformance to the card's requirements for key length.
*
@@ -737,7 +762,6 @@ public abstract class BaseNfcActivity extends BaseActivity {
+ getHex(newPin);
String response = nfcCommunicate(changeReferenceDataApdu); // change PIN
if (!response.equals("9000")) {
- handlePinError();
throw new CardException("Failed to change PIN", parseCardStatus(response));
}
}
@@ -906,15 +930,6 @@ public abstract class BaseNfcActivity extends BaseActivity {
}
/**
- * Prints a message to the screen
- *
- * @param text the text which should be contained within the toast
- */
- protected void toast(String text) {
- Toast.makeText(this, text, Toast.LENGTH_LONG).show();
- }
-
- /**
* Receive new NFC Intents to this activity only by enabling foreground dispatch.
* This can only be done in onResume!
*/
@@ -930,12 +945,10 @@ public abstract class BaseNfcActivity extends BaseActivity {
new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED)
};
- // https://code.google.com/p/android/issues/detail?id=62918
- // maybe mNfcAdapter.enableReaderMode(); ?
try {
mNfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, writeTagFilters, null);
} catch (IllegalStateException e) {
- Log.i(Constants.TAG, "NfcForegroundDispatch Error!", e);
+ Log.i(Constants.TAG, "NfcForegroundDispatch Exception: Activity is not currently in the foreground?", e);
}
Log.d(Constants.TAG, "NfcForegroundDispatch has been enabled!");
}
@@ -952,14 +965,23 @@ public abstract class BaseNfcActivity extends BaseActivity {
}
public String nfcGetHolderName(String name) {
- String slength;
- int ilength;
- name = name.substring(6);
- slength = name.substring(0, 2);
- ilength = Integer.parseInt(slength, 16) * 2;
- name = name.substring(2, ilength + 2);
- name = (new String(Hex.decode(name))).replace('<', ' ');
- return (name);
+ try {
+ String slength;
+ int ilength;
+ name = name.substring(6);
+ slength = name.substring(0, 2);
+ ilength = Integer.parseInt(slength, 16) * 2;
+ name = name.substring(2, ilength + 2);
+ name = (new String(Hex.decode(name))).replace('<', ' ');
+ return name;
+ } catch (IndexOutOfBoundsException e) {
+ // try-catch for https://github.com/FluffyKaon/OpenPGP-Card
+ // Note: This should not happen, but happens with
+ // https://github.com/FluffyKaon/OpenPGP-Card, thus return an empty string for now!
+
+ Log.e(Constants.TAG, "Couldn't get holder name, returning empty string!", e);
+ return "";
+ }
}
private String nfcGetDataField(String output) {
@@ -974,6 +996,14 @@ public abstract class BaseNfcActivity extends BaseActivity {
return new String(Hex.encode(raw));
}
+ public class IsoDepNotSupportedException extends IOException {
+
+ public IsoDepNotSupportedException(String detailMessage) {
+ super(detailMessage);
+ }
+
+ }
+
public class CardException extends IOException {
private short mResponseCode;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java
index 52c6797d5..7ab9c7237 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java
@@ -84,6 +84,7 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
public static final int REQUEST_CODE_RETRY_UPLOAD = 4;
private Integer mProgressMessageResource;
+ private boolean mCancellable = false;
private FragmentActivity mActivity;
private Fragment mFragment;
@@ -118,6 +119,10 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
mProgressMessageResource = id;
}
+ public void setProgressCancellable(boolean cancellable) {
+ mCancellable = cancellable;
+ }
+
private void initiateInputActivity(RequiredInputParcel requiredInput,
CryptoInputParcel cryptoInputParcel) {
@@ -136,7 +141,8 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
}
case PASSPHRASE:
- case PASSPHRASE_SYMMETRIC: {
+ case PASSPHRASE_SYMMETRIC:
+ case BACKUP_CODE: {
Intent intent = new Intent(activity, PassphraseDialogActivity.class);
intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput);
intent.putExtra(PassphraseDialogActivity.EXTRA_CRYPTO_INPUT, cryptoInputParcel);
@@ -310,7 +316,7 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
if (mProgressMessageResource != null) {
saveHandler.showProgressDialog(
activity.getString(mProgressMessageResource),
- ProgressDialog.STYLE_HORIZONTAL, false);
+ ProgressDialog.STYLE_HORIZONTAL, mCancellable);
}
activity.startService(intent);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java
index 47bc7dfda..3d96f3c6d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddEditKeyserverDialogFragment.java
@@ -24,6 +24,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import android.app.Activity;
+import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
@@ -44,6 +45,7 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.CheckBox;
+import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
@@ -54,6 +56,7 @@ import com.squareup.okhttp.Request;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
+import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Preferences;
import org.sufficientlysecure.keychain.util.TlsHelper;
@@ -68,11 +71,9 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On
private static final String ARG_KEYSERVER = "arg_keyserver";
public static final int MESSAGE_OKAY = 1;
- public static final int MESSAGE_VERIFICATION_FAILED = 2;
public static final String MESSAGE_KEYSERVER = "new_keyserver";
public static final String MESSAGE_VERIFIED = "verified";
- public static final String MESSAGE_FAILURE_REASON = "failure_reason";
public static final String MESSAGE_KEYSERVER_DELETED = "keyserver_deleted";
public static final String MESSAGE_DIALOG_ACTION = "message_dialog_action";
public static final String MESSAGE_EDIT_POSITION = "keyserver_edited_position";
@@ -82,7 +83,9 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On
private int mPosition;
private EditText mKeyserverEditText;
+ private TextInputLayout mKeyserverEditTextLayout;
private CheckBox mVerifyKeyserverCheckBox;
+ private CheckBox mOnlyTrustedKeyserverCheckBox;
public enum DialogAction {
ADD,
@@ -91,7 +94,8 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On
public enum FailureReason {
INVALID_URL,
- CONNECTION_FAILED
+ CONNECTION_FAILED,
+ NO_PINNED_CERTIFICATE
}
public static AddEditKeyserverDialogFragment newInstance(Messenger messenger,
@@ -126,7 +130,15 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On
alert.setView(view);
mKeyserverEditText = (EditText) view.findViewById(R.id.keyserver_url_edit_text);
- mVerifyKeyserverCheckBox = (CheckBox) view.findViewById(R.id.verify_keyserver_checkbox);
+ mKeyserverEditTextLayout = (TextInputLayout) view.findViewById(R.id.keyserver_url_edit_text_layout);
+ mVerifyKeyserverCheckBox = (CheckBox) view.findViewById(R.id.verify_connection_checkbox);
+ mOnlyTrustedKeyserverCheckBox = (CheckBox) view.findViewById(R.id.only_trusted_keyserver_checkbox);
+ mVerifyKeyserverCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ mOnlyTrustedKeyserverCheckBox.setEnabled(isChecked);
+ }
+ });
switch (mDialogAction) {
case ADD: {
@@ -212,6 +224,8 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On
positiveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
+ mKeyserverEditTextLayout.setErrorEnabled(false);
+
// behaviour same for edit and add
final String keyserverUrl = mKeyserverEditText.getText().toString();
if (mVerifyKeyserverCheckBox.isChecked()) {
@@ -220,13 +234,20 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On
OrbotHelper.DialogActions dialogActions = new OrbotHelper.DialogActions() {
@Override
public void onOrbotStarted() {
- verifyConnection(keyserverUrl,
- proxyPrefs.parcelableProxy.getProxy());
+ verifyConnection(
+ keyserverUrl,
+ proxyPrefs.parcelableProxy.getProxy(),
+ mOnlyTrustedKeyserverCheckBox.isChecked()
+ );
}
@Override
public void onNeutralButton() {
- verifyConnection(keyserverUrl, null);
+ verifyConnection(
+ keyserverUrl,
+ null,
+ mOnlyTrustedKeyserverCheckBox.isChecked()
+ );
}
@Override
@@ -236,7 +257,11 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On
};
if (OrbotHelper.putOrbotInRequiredState(dialogActions, getActivity())) {
- verifyConnection(keyserverUrl, proxyPrefs.parcelableProxy.getProxy());
+ verifyConnection(
+ keyserverUrl,
+ proxyPrefs.parcelableProxy.getProxy(),
+ mOnlyTrustedKeyserverCheckBox.isChecked()
+ );
}
} else {
dismiss();
@@ -272,14 +297,28 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On
sendMessageToHandler(MESSAGE_OKAY, data);
}
- public void verificationFailed(FailureReason reason) {
- Bundle data = new Bundle();
- data.putSerializable(MESSAGE_FAILURE_REASON, reason);
+ public void verificationFailed(FailureReason failureReason) {
+ switch (failureReason) {
+ case CONNECTION_FAILED: {
+ mKeyserverEditTextLayout.setError(
+ getString(R.string.add_keyserver_connection_failed));
+ break;
+ }
+ case INVALID_URL: {
+ mKeyserverEditTextLayout.setError(
+ getString(R.string.add_keyserver_invalid_url));
+ break;
+ }
+ case NO_PINNED_CERTIFICATE: {
+ mKeyserverEditTextLayout.setError(
+ getString(R.string.add_keyserver_keyserver_not_trusted));
+ break;
+ }
+ }
- sendMessageToHandler(MESSAGE_VERIFICATION_FAILED, data);
}
- public void verifyConnection(String keyserver, final Proxy proxy) {
+ public void verifyConnection(String keyserver, final Proxy proxy, final boolean onlyTrustedKeyserver) {
new AsyncTask<String, Void, FailureReason>() {
ProgressDialog mProgressDialog;
@@ -288,7 +327,7 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On
@Override
protected void onPreExecute() {
mProgressDialog = new ProgressDialog(getActivity());
- mProgressDialog.setMessage(getString(R.string.progress_verifying_keyserver_url));
+ mProgressDialog.setMessage(getString(R.string.progress_verifying_keyserver_connection));
mProgressDialog.setCancelable(false);
mProgressDialog.show();
}
@@ -316,7 +355,18 @@ public class AddEditKeyserverDialogFragment extends DialogFragment implements On
Log.d("Converted URL", newKeyserver.toString());
OkHttpClient client = HkpKeyserver.getClient(newKeyserver.toURL(), proxy);
- TlsHelper.pinCertificateIfNecessary(client, newKeyserver.toURL());
+
+ // don't follow any redirects
+ client.setFollowRedirects(false);
+ client.setFollowSslRedirects(false);
+
+ if (onlyTrustedKeyserver
+ && !TlsHelper.usePinnedCertificateIfAvailable(client, newKeyserver.toURL())) {
+ Log.w(Constants.TAG, "No pinned certificate for this host in OpenKeychain's assets.");
+ reason = FailureReason.NO_PINNED_CERTIFICATE;
+ return reason;
+ }
+
client.newCall(new Request.Builder().url(newKeyserver.toURL()).build()).execute();
} catch (TlsHelper.TlsHelperException e) {
reason = FailureReason.CONNECTION_FAILED;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
index b51d081e1..cd5281c7c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java
@@ -348,30 +348,30 @@ public class AddSubkeyDialogFragment extends DialogFragment {
/**
* <h3>RSA</h3>
- * <p>for RSA algorithm, key length must be greater than 1024 (according to
- * <a href="https://github.com/open-keychain/open-keychain/issues/102">#102</a>). Possibility to generate keys bigger
+ * <p>for RSA algorithm, key length must be greater than 2048. Possibility to generate keys bigger
* than 8192 bits is currently disabled, because it's almost impossible to generate them on a mobile device (check
* <a href="http://www.javamex.com/tutorials/cryptography/rsa_key_length.shtml">RSA key length plot</a> and
* <a href="http://www.keylength.com/">Cryptographic Key Length Recommendation</a>). Also, key length must be a
* multiplicity of 8.</p>
* <h3>ElGamal</h3>
- * <p>For ElGamal algorithm, supported key lengths are 1536, 2048, 3072, 4096 or 8192 bits.</p>
+ * <p>For ElGamal algorithm, supported key lengths are 2048, 3072, 4096 or 8192 bits.</p>
* <h3>DSA</h3>
- * <p>For DSA algorithm key length must be between 512 and 1024. Also, it must me dividable by 64.</p>
+ * <p>For DSA algorithm key length must be between 2048 and 3072. Also, it must me dividable by 64.</p>
*
* @return correct key length, according to SpongyCastle specification. Returns <code>-1</code>, if key length is
* inappropriate.
*/
private int getProperKeyLength(Algorithm algorithm, int currentKeyLength) {
- final int[] elGamalSupportedLengths = {1536, 2048, 3072, 4096, 8192};
+ final int[] elGamalSupportedLengths = {2048, 3072, 4096, 8192};
int properKeyLength = -1;
switch (algorithm) {
- case RSA:
- if (currentKeyLength > 1024 && currentKeyLength <= 16384) {
+ case RSA: {
+ if (currentKeyLength >= 2048 && currentKeyLength <= 16384) {
properKeyLength = currentKeyLength + ((8 - (currentKeyLength % 8)) % 8);
}
break;
- case ELGAMAL:
+ }
+ case ELGAMAL: {
int[] elGammalKeyDiff = new int[elGamalSupportedLengths.length];
for (int i = 0; i < elGamalSupportedLengths.length; i++) {
elGammalKeyDiff[i] = Math.abs(elGamalSupportedLengths[i] - currentKeyLength);
@@ -386,11 +386,14 @@ public class AddSubkeyDialogFragment extends DialogFragment {
}
properKeyLength = elGamalSupportedLengths[minimalIndex];
break;
- case DSA:
- if (currentKeyLength >= 512 && currentKeyLength <= 1024) {
+ }
+ case DSA: {
+ // Bouncy Castle supports 4096 maximum
+ if (currentKeyLength >= 2048 && currentKeyLength <= 4096) {
properKeyLength = currentKeyLength + ((64 - (currentKeyLength % 64)) % 64);
}
break;
+ }
}
return properKeyLength;
}
@@ -424,7 +427,7 @@ public class AddSubkeyDialogFragment extends DialogFragment {
final ArrayAdapter<CharSequence> keySizeAdapter = (ArrayAdapter<CharSequence>) mKeySizeSpinner.getAdapter();
keySizeAdapter.clear();
switch (algorithm) {
- case RSA:
+ case RSA: {
replaceArrayAdapterContent(keySizeAdapter, R.array.rsa_key_size_spinner_values);
mKeySizeSpinner.setSelection(1);
mKeySizeRow.setVisibility(View.VISIBLE);
@@ -450,7 +453,8 @@ public class AddSubkeyDialogFragment extends DialogFragment {
}
mFlagAuthenticate.setChecked(false);
break;
- case ELGAMAL:
+ }
+ case ELGAMAL: {
replaceArrayAdapterContent(keySizeAdapter, R.array.elgamal_key_size_spinner_values);
mKeySizeSpinner.setSelection(3);
mKeySizeRow.setVisibility(View.VISIBLE);
@@ -466,7 +470,8 @@ public class AddSubkeyDialogFragment extends DialogFragment {
mFlagAuthenticate.setChecked(false);
mFlagAuthenticate.setEnabled(false);
break;
- case DSA:
+ }
+ case DSA: {
replaceArrayAdapterContent(keySizeAdapter, R.array.dsa_key_size_spinner_values);
mKeySizeSpinner.setSelection(2);
mKeySizeRow.setVisibility(View.VISIBLE);
@@ -482,7 +487,8 @@ public class AddSubkeyDialogFragment extends DialogFragment {
mFlagAuthenticate.setChecked(false);
mFlagAuthenticate.setEnabled(false);
break;
- case ECDSA:
+ }
+ case ECDSA: {
mKeySizeRow.setVisibility(View.GONE);
mCurveRow.setVisibility(View.VISIBLE);
mCustomKeyInfoTextView.setText("");
@@ -496,7 +502,8 @@ public class AddSubkeyDialogFragment extends DialogFragment {
mFlagAuthenticate.setEnabled(true);
mFlagAuthenticate.setChecked(false);
break;
- case ECDH:
+ }
+ case ECDH: {
mKeySizeRow.setVisibility(View.GONE);
mCurveRow.setVisibility(View.VISIBLE);
mCustomKeyInfoTextView.setText("");
@@ -510,6 +517,7 @@ public class AddSubkeyDialogFragment extends DialogFragment {
mFlagAuthenticate.setChecked(false);
mFlagAuthenticate.setEnabled(false);
break;
+ }
}
keySizeAdapter.notifyDataSetChanged();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java
deleted file mode 100644
index 84774ae5e..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.ui.dialog;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.support.v4.app.DialogFragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.TextView;
-
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.ui.util.Notify;
-import org.sufficientlysecure.keychain.util.FileHelper;
-import org.sufficientlysecure.keychain.util.Log;
-
-import java.io.File;
-
-/**
- * This is a file chooser dialog no longer used with KitKat
- */
-public class FileDialogFragment extends DialogFragment {
- private static final String ARG_MESSENGER = "messenger";
- private static final String ARG_TITLE = "title";
- private static final String ARG_MESSAGE = "message";
- private static final String ARG_DEFAULT_FILE = "default_file";
- private static final String ARG_CHECKBOX_TEXT = "checkbox_text";
-
- public static final int MESSAGE_OKAY = 1;
-
- public static final String MESSAGE_DATA_FILE = "file";
- public static final String MESSAGE_DATA_CHECKED = "checked";
-
- private Messenger mMessenger;
-
- private EditText mFilename;
- private ImageButton mBrowse;
- private CheckBox mCheckBox;
- private TextView mMessageTextView;
-
- private File mFile;
-
- private static final int REQUEST_CODE = 0x00007004;
-
- /**
- * Creates new instance of this file dialog fragment
- */
- public static FileDialogFragment newInstance(Messenger messenger, String title, String message,
- File defaultFile, String checkboxText) {
- FileDialogFragment frag = new FileDialogFragment();
- Bundle args = new Bundle();
- args.putParcelable(ARG_MESSENGER, messenger);
-
- args.putString(ARG_TITLE, title);
- args.putString(ARG_MESSAGE, message);
- args.putString(ARG_DEFAULT_FILE, defaultFile.getAbsolutePath());
- args.putString(ARG_CHECKBOX_TEXT, checkboxText);
-
- frag.setArguments(args);
-
- return frag;
- }
-
- /**
- * Creates dialog
- */
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- final Activity activity = getActivity();
-
- mMessenger = getArguments().getParcelable(ARG_MESSENGER);
-
- String title = getArguments().getString(ARG_TITLE);
- String message = getArguments().getString(ARG_MESSAGE);
- mFile = new File(getArguments().getString(ARG_DEFAULT_FILE));
- if (!mFile.isAbsolute()) {
- // We use OK dir by default
- mFile = new File(Constants.Path.APP_DIR.getAbsolutePath(), mFile.getName());
- }
- String checkboxText = getArguments().getString(ARG_CHECKBOX_TEXT);
-
- LayoutInflater inflater = (LayoutInflater) activity
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
- alert.setTitle(title);
-
- View view = inflater.inflate(R.layout.file_dialog, null);
-
- mMessageTextView = (TextView) view.findViewById(R.id.message);
- mMessageTextView.setText(message);
-
- mFilename = (EditText) view.findViewById(R.id.input);
- mFilename.setText(mFile.getName());
- mBrowse = (ImageButton) view.findViewById(R.id.btn_browse);
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
- mBrowse.setVisibility(View.GONE);
- } else {
- mBrowse.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- // only .asc or .gpg files
- // setting it to text/plain prevents Cynaogenmod's file manager from selecting asc
- // or gpg types!
- FileHelper.saveDocumentKitKat(
- FileDialogFragment.this, "*/*", mFile.getName(), REQUEST_CODE);
- }
- });
- }
-
- mCheckBox = (CheckBox) view.findViewById(R.id.checkbox);
- if (checkboxText == null) {
- mCheckBox.setEnabled(false);
- mCheckBox.setVisibility(View.GONE);
- } else {
- mCheckBox.setEnabled(true);
- mCheckBox.setVisibility(View.VISIBLE);
- mCheckBox.setText(checkboxText);
- mCheckBox.setChecked(true);
- }
-
- alert.setView(view);
-
- alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dismiss();
-
- String currentFilename = mFilename.getText().toString();
- if (currentFilename == null || currentFilename.isEmpty()) {
- // No file is like pressing cancel, UI: maybe disable positive button in this case?
- return;
- }
-
- if (mFile == null || currentFilename.startsWith("/")) {
- mFile = new File(currentFilename);
- } else if (!mFile.getName().equals(currentFilename)) {
- // We update our File object if user changed name!
- mFile = new File(mFile.getParentFile(), currentFilename);
- }
-
- boolean checked = mCheckBox.isEnabled() && mCheckBox.isChecked();
-
- // return resulting data back to activity
- Bundle data = new Bundle();
- data.putString(MESSAGE_DATA_FILE, mFile.getAbsolutePath());
- data.putBoolean(MESSAGE_DATA_CHECKED, checked);
-
- sendMessageToHandler(MESSAGE_OKAY, data);
- }
- });
-
- alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dismiss();
- }
- });
- return alert.show();
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode & 0xFFFF) {
- case REQUEST_CODE: {
- if (resultCode == Activity.RESULT_OK && data != null) {
- File file = new File(data.getData().getPath());
- if (file.getParentFile().exists()) {
- mFile = file;
- mFilename.setText(mFile.getName());
- } else {
- Notify.create(getActivity(), R.string.no_file_selected, Notify.Style.ERROR).show();
- }
- }
-
- break;
- }
-
- default:
- super.onActivityResult(requestCode, resultCode, data);
-
- break;
- }
- }
-
- /**
- * Send message back to handler which is initialized in a activity
- *
- * @param what Message integer you want to send
- */
- private void sendMessageToHandler(Integer what, Bundle data) {
- Message msg = Message.obtain();
- msg.what = what;
- if (data != null) {
- msg.setData(data);
- }
-
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.w(Constants.TAG, "Exception sending message, Is handler present?", e);
- } catch (NullPointerException e) {
- Log.w(Constants.TAG, "Messenger is null!", e);
- }
- }
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareLogDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareLogDialogFragment.java
new file mode 100644
index 000000000..d4783fad2
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareLogDialogFragment.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui.dialog;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.DialogFragment;
+import android.view.ContextThemeWrapper;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
+
+public class ShareLogDialogFragment extends DialogFragment {
+ private static final String ARG_STREAM = "stream";
+
+ public static ShareLogDialogFragment newInstance(Uri stream) {
+ Bundle args = new Bundle();
+ args.putParcelable(ARG_STREAM, stream);
+
+ ShareLogDialogFragment fragment = new ShareLogDialogFragment();
+ fragment.setArguments(args);
+
+ return fragment;
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+
+ final Uri stream = getArguments().getParcelable(ARG_STREAM);
+
+ ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(getActivity());
+
+ CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(theme);
+ builder.setTitle(R.string.share_log_dialog_title)
+ .setMessage(R.string.share_log_dialog_message)
+ .setNegativeButton(R.string.share_log_dialog_cancel_button,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dismiss();
+ }
+ })
+ .setPositiveButton(R.string.share_log_dialog_share_button,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dismiss();
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.putExtra(Intent.EXTRA_STREAM, stream);
+ intent.setType("text/plain");
+ intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ startActivity(intent);
+ }
+ });
+
+ return builder.show();
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java
index 22a201ba3..a320ea3b2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java
@@ -27,7 +27,6 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.EditText;
-import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.linked.resources.GenericHttpsResource;
@@ -35,7 +34,6 @@ import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.FileHelper;
-import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.net.URI;
@@ -134,10 +132,8 @@ public class LinkedIdCreateHttpsStep2Fragment extends LinkedIdCreateFinalFragmen
String targetName = "pgpkey.txt";
- FileHelper.saveDocument(this,
- targetName, Uri.fromFile(new File(Constants.Path.APP_DIR, targetName)),
- "text/plain", R.string.title_decrypt_to_file, R.string.specify_file_to_decrypt_to,
- REQUEST_CODE_OUTPUT);
+ // TODO: not supported on Android < 4.4
+ FileHelper.saveDocument(this, targetName, "text/plain", REQUEST_CODE_OUTPUT);
}
private void saveFile(Uri uri) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java
index 8f5753dae..b9b837d71 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java
@@ -28,6 +28,7 @@ import android.text.style.ForegroundColorSpan;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
+import android.widget.ViewAnimator;
import org.openintents.openpgp.OpenPgpDecryptionResult;
import org.openintents.openpgp.OpenPgpSignatureResult;
@@ -440,14 +441,15 @@ public class KeyFormattingUtils {
View getSignatureLayout();
TextView getSignatureUserName();
TextView getSignatureUserEmail();
- TextView getSignatureAction();
+ ViewAnimator getSignatureAction();
boolean hasEncrypt();
}
@SuppressWarnings("deprecation") // context.getDrawable is api lvl 21, need to use deprecated
- public static void setStatus(Resources resources, StatusHolder holder, DecryptVerifyResult result) {
+ public static void setStatus(Resources resources, StatusHolder holder, DecryptVerifyResult result,
+ boolean processingkeyLookup) {
if (holder.hasEncrypt()) {
OpenPgpDecryptionResult decryptionResult = result.getDecryptionResult();
@@ -488,7 +490,7 @@ public class KeyFormattingUtils {
OpenPgpSignatureResult signatureResult = result.getSignatureResult();
int sigText, sigIcon, sigColor;
- int sigActionText, sigActionIcon;
+ int sigActionDisplayedChild;
switch (signatureResult.getResult()) {
@@ -500,8 +502,7 @@ public class KeyFormattingUtils {
sigColor = R.color.key_flag_gray;
// won't be used, but makes compiler happy
- sigActionText = 0;
- sigActionIcon = 0;
+ sigActionDisplayedChild = -1;
break;
}
@@ -510,8 +511,7 @@ public class KeyFormattingUtils {
sigIcon = R.drawable.status_signature_verified_cutout_24dp;
sigColor = R.color.key_flag_green;
- sigActionText = R.string.decrypt_result_action_show;
- sigActionIcon = R.drawable.ic_vpn_key_grey_24dp;
+ sigActionDisplayedChild = 0;
break;
}
@@ -520,8 +520,7 @@ public class KeyFormattingUtils {
sigIcon = R.drawable.status_signature_unverified_cutout_24dp;
sigColor = R.color.key_flag_orange;
- sigActionText = R.string.decrypt_result_action_show;
- sigActionIcon = R.drawable.ic_vpn_key_grey_24dp;
+ sigActionDisplayedChild = 0;
break;
}
@@ -530,8 +529,7 @@ public class KeyFormattingUtils {
sigIcon = R.drawable.status_signature_revoked_cutout_24dp;
sigColor = R.color.key_flag_red;
- sigActionText = R.string.decrypt_result_action_show;
- sigActionIcon = R.drawable.ic_vpn_key_grey_24dp;
+ sigActionDisplayedChild = 0;
break;
}
@@ -540,8 +538,7 @@ public class KeyFormattingUtils {
sigIcon = R.drawable.status_signature_expired_cutout_24dp;
sigColor = R.color.key_flag_red;
- sigActionText = R.string.decrypt_result_action_show;
- sigActionIcon = R.drawable.ic_vpn_key_grey_24dp;
+ sigActionDisplayedChild = 0;
break;
}
@@ -550,8 +547,7 @@ public class KeyFormattingUtils {
sigIcon = R.drawable.status_signature_unknown_cutout_24dp;
sigColor = R.color.key_flag_red;
- sigActionText = R.string.decrypt_result_action_Lookup;
- sigActionIcon = R.drawable.ic_file_download_grey_24dp;
+ sigActionDisplayedChild = 1;
break;
}
@@ -560,8 +556,7 @@ public class KeyFormattingUtils {
sigIcon = R.drawable.status_signature_invalid_cutout_24dp;
sigColor = R.color.key_flag_red;
- sigActionText = R.string.decrypt_result_action_show;
- sigActionIcon = R.drawable.ic_vpn_key_grey_24dp;
+ sigActionDisplayedChild = 0;
break;
}
@@ -571,27 +566,31 @@ public class KeyFormattingUtils {
sigIcon = R.drawable.status_signature_invalid_cutout_24dp;
sigColor = R.color.key_flag_red;
- sigActionText = R.string.decrypt_result_action_show;
- sigActionIcon = R.drawable.ic_vpn_key_grey_24dp;
+ // won't be used, but makes compiler happy
+ sigActionDisplayedChild = -1;
break;
}
}
+ // possibly switch out "Lookup" button for progress bar
+ if (sigActionDisplayedChild == 1 && processingkeyLookup) {
+ sigActionDisplayedChild = 2;
+ }
+
int sigColorRes = resources.getColor(sigColor);
holder.getSignatureStatusIcon().setColorFilter(sigColorRes, PorterDuff.Mode.SRC_IN);
holder.getSignatureStatusIcon().setImageDrawable(resources.getDrawable(sigIcon));
holder.getSignatureStatusText().setText(sigText);
holder.getSignatureStatusText().setTextColor(sigColorRes);
- if (signatureResult.getResult() != OpenPgpSignatureResult.RESULT_NO_SIGNATURE) {
+ if (signatureResult.getResult() != OpenPgpSignatureResult.RESULT_NO_SIGNATURE
+ && signatureResult.getResult() != OpenPgpSignatureResult.RESULT_INVALID_SIGNATURE) {
// has a signature, thus display layouts
holder.getSignatureLayout().setVisibility(View.VISIBLE);
- holder.getSignatureAction().setText(sigActionText);
- holder.getSignatureAction().setCompoundDrawablesWithIntrinsicBounds(
- 0, 0, sigActionIcon, 0);
+ holder.getSignatureAction().setDisplayedChild(sigActionDisplayedChild);
String userId = result.getSignatureResult().getPrimaryUserId();
KeyRing.UserId userIdSplit = KeyRing.splitUserId(userId);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java
index 7dfd56430..71f6ecc1a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java
@@ -37,7 +37,7 @@ import org.sufficientlysecure.keychain.util.FabContainer;
*/
public class Notify {
- public static enum Style {
+ public enum Style {
OK (R.color.android_green_light), WARN(R.color.android_orange_light), ERROR(R.color.android_red_light);
public final int mLineColor;
@@ -142,6 +142,11 @@ public class Notify {
return create(activity, text, LENGTH_LONG, style);
}
+ public static Showable create(Activity activity, int textResId, Style style,
+ ActionListener actionListener, int actionResId) {
+ return create(activity, textResId, LENGTH_LONG, style, actionListener, actionResId);
+ }
+
public static Showable create(Activity activity, int textResId, int duration, Style style,
ActionListener actionListener, int actionResId) {
return create(activity, activity.getString(textResId), duration, style, actionListener, actionResId);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java
index 48e6c2cee..01d51af48 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java
@@ -23,11 +23,13 @@ import android.database.Cursor;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -46,14 +48,14 @@ import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter.KeyItem;
import org.sufficientlysecure.keychain.util.Log;
-public class EncryptKeyCompletionView extends TokenCompleteTextView
+public class EncryptKeyCompletionView extends TokenCompleteTextView<KeyItem>
implements LoaderCallbacks<Cursor> {
public static final String ARG_QUERY = "query";
private KeyAdapter mAdapter;
private LoaderManager mLoaderManager;
- private String mPrefix;
+ private CharSequence mPrefix;
public EncryptKeyCompletionView(Context context) {
super(context);
@@ -79,30 +81,27 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView
}
@Override
- public void setPrefix(String p) {
+ public void setPrefix(CharSequence p) {
// this one is private in the superclass, but we need it here
mPrefix = p;
super.setPrefix(p);
}
@Override
- protected View getViewForObject(Object object) {
- if (object instanceof KeyItem) {
- LayoutInflater l = LayoutInflater.from(getContext());
- View view = l.inflate(R.layout.recipient_box_entry, null);
- ((TextView) view.findViewById(android.R.id.text1)).setText(((KeyItem) object).getReadableName());
- return view;
- }
- return null;
+ protected View getViewForObject(KeyItem keyItem) {
+ LayoutInflater l = LayoutInflater.from(getContext());
+ View view = l.inflate(R.layout.recipient_box_entry, null);
+ ((TextView) view.findViewById(android.R.id.text1)).setText(keyItem.getReadableName());
+ return view;
}
@Override
- protected Object defaultObject(String completionText) {
+ protected KeyItem defaultObject(String completionText) {
// TODO: We could try to automagically download the key if it's unknown but a key id
/*if (completionText.startsWith("0x")) {
}*/
- return "";
+ return null;
}
@Override
@@ -128,7 +127,7 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView
// These are the rows that we will retrieve.
Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();
- String[] projection = KeyAdapter.getProjectionWith(new String[] {
+ String[] projection = KeyAdapter.getProjectionWith(new String[]{
KeychainContract.KeyRings.HAS_ENCRYPT,
});
@@ -136,18 +135,19 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView
+ KeyRings.IS_EXPIRED + " = 0 AND "
+ Tables.KEYS + "." + KeyRings.IS_REVOKED + " = 0";
- if (args != null && args.containsKey(ARG_QUERY)) {
- String query = args.getString(ARG_QUERY);
- mAdapter.setSearchQuery(query);
+ if (args == null || !args.containsKey(ARG_QUERY)) {
+ // mAdapter.setSearchQuery(null);
+ // return new CursorLoader(getContext(), baseUri, projection, where, null, null);
+ return null;
+ }
- where += " AND " + KeyRings.USER_ID + " LIKE ?";
+ String query = args.getString(ARG_QUERY);
+ mAdapter.setSearchQuery(query);
- return new CursorLoader(getContext(), baseUri, projection, where,
- new String[]{"%" + query + "%"}, null);
- }
+ where += " AND " + KeyRings.USER_ID + " LIKE ?";
- mAdapter.setSearchQuery(null);
- return new CursorLoader(getContext(), baseUri, projection, where, null, null);
+ return new CursorLoader(getContext(), baseUri, projection, where,
+ new String[]{"%" + query + "%"}, null);
}
@@ -169,6 +169,8 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView
super.showDropDown();
}
+
+
@Override
public void onFocusChanged(boolean hasFocus, int direction, Rect previous) {
super.onFocusChanged(hasFocus, direction, previous);
@@ -179,13 +181,18 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView
}
@Override
- protected void performFiltering(CharSequence text, int start, int end, int keyCode) {
+ protected void performFiltering(@NonNull CharSequence text, int start, int end, int keyCode) {
super.performFiltering(text, start, end, keyCode);
if (start < mPrefix.length()) {
start = mPrefix.length();
}
+ String query = text.subSequence(start, end).toString();
+ if (TextUtils.isEmpty(query) || query.length() < 2) {
+ mLoaderManager.destroyLoader(0);
+ return;
+ }
Bundle args = new Bundle();
- args.putString(ARG_QUERY, text.subSequence(start, end).toString());
+ args.putString(ARG_QUERY, query);
mLoaderManager.restartLoader(0, args, this);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ToolableViewAnimator.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ToolableViewAnimator.java
index 18e830139..a8274e45a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ToolableViewAnimator.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ToolableViewAnimator.java
@@ -31,6 +31,7 @@ import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.Animation;
import android.widget.ViewAnimator;
import org.sufficientlysecure.keychain.R;
@@ -73,4 +74,29 @@ public class ToolableViewAnimator extends ViewAnimator {
}
super.addView(child, index, params);
}
+
+ @Override
+ public void setDisplayedChild(int whichChild) {
+ if (whichChild != getDisplayedChild()) {
+ super.setDisplayedChild(whichChild);
+ }
+ }
+
+ public void setDisplayedChild(int whichChild, boolean animate) {
+ if (animate) {
+ setDisplayedChild(whichChild);
+ return;
+ }
+
+ Animation savedInAnim = getInAnimation();
+ Animation savedOutAnim = getOutAnimation();
+ setInAnimation(null);
+ setOutAnimation(null);
+
+ setDisplayedChild(whichChild);
+
+ setInAnimation(savedInAnim);
+ setOutAnimation(savedOutAnim);
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java
index d7491ab26..a55249842 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java
@@ -74,9 +74,9 @@ public class EmailKeyHelper {
// Try _hkp._tcp SRV record first
String[] mailparts = mail.split("@");
if (mailparts.length == 2) {
- HkpKeyserver hkp = HkpKeyserver.resolve(mailparts[1]);
+ HkpKeyserver hkp = HkpKeyserver.resolve(mailparts[1], proxy);
if (hkp != null) {
- keys.addAll(getEmailKeys(mail, hkp, proxy));
+ keys.addAll(getEmailKeys(mail, hkp));
}
}
@@ -84,18 +84,17 @@ public class EmailKeyHelper {
// Most users don't have the SRV record, so ask a default server as well
String server = Preferences.getPreferences(context).getPreferredKeyserver();
if (server != null) {
- HkpKeyserver hkp = new HkpKeyserver(server);
- keys.addAll(getEmailKeys(mail, hkp, proxy));
+ HkpKeyserver hkp = new HkpKeyserver(server, proxy);
+ keys.addAll(getEmailKeys(mail, hkp));
}
}
return keys;
}
- public static List<ImportKeysListEntry> getEmailKeys(String mail, Keyserver keyServer,
- Proxy proxy) {
+ public static List<ImportKeysListEntry> getEmailKeys(String mail, Keyserver keyServer) {
Set<ImportKeysListEntry> keys = new HashSet<>();
try {
- for (ImportKeysListEntry key : keyServer.search(mail, proxy)) {
+ for (ImportKeysListEntry key : keyServer.search(mail)) {
if (key.isRevoked() || key.isExpired()) continue;
for (String userId : key.getUserIds()) {
if (userId.toLowerCase().contains(mail.toLowerCase(Locale.ENGLISH))) {
@@ -103,8 +102,7 @@ public class EmailKeyHelper {
}
}
}
- } catch (Keyserver.QueryFailedException ignored) {
- } catch (Keyserver.QueryNeedsRepairException ignored) {
+ } catch (Keyserver.CloudSearchFailureException ignored) {
}
return new ArrayList<>(keys);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java
deleted file mode 100644
index 45dc33906..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.util;
-
-
-import java.io.File;
-
-import android.content.Intent;
-import android.net.Uri;
-import android.support.v4.app.FragmentActivity;
-
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.operations.results.ExportResult;
-import org.sufficientlysecure.keychain.service.ExportKeyringParcel;
-import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
-
-public class ExportHelper
- implements CryptoOperationHelper.Callback <ExportKeyringParcel, ExportResult> {
- protected File mExportFile;
-
- FragmentActivity mActivity;
-
- private boolean mExportSecret;
- private long[] mMasterKeyIds;
-
- public ExportHelper(FragmentActivity activity) {
- super();
- this.mActivity = activity;
- }
-
- /** Show dialog where to export keys */
- public void showExportKeysDialog(final Long masterKeyId, final File exportFile,
- final boolean exportSecret) {
- mExportFile = exportFile;
-
- String title;
- if (masterKeyId == null) {
- // export all keys
- title = mActivity.getString(R.string.title_export_keys);
- } else {
- // export only key specified at data uri
- title = mActivity.getString(R.string.title_export_key);
- }
-
- String message;
- if (exportSecret) {
- message = mActivity.getString(masterKeyId == null
- ? R.string.specify_backup_dest_secret
- : R.string.specify_backup_dest_secret_single);
- } else {
- message = mActivity.getString(masterKeyId == null
- ? R.string.specify_backup_dest
- : R.string.specify_backup_dest_single);
- }
-
- FileHelper.saveDocumentDialog(new FileHelper.FileDialogCallback() {
- @Override
- public void onFileSelected(File file, boolean checked) {
- mExportFile = file;
- exportKeys(masterKeyId == null ? null : new long[] { masterKeyId }, exportSecret);
- }
- }, mActivity.getSupportFragmentManager(), title, message, exportFile, null);
- }
-
- // TODO: If ExportHelper requires pending data (see CryptoOPerationHelper), activities using
- // TODO: this class should be able to call mExportOpHelper.handleActivity
-
- /**
- * Export keys
- */
- public void exportKeys(long[] masterKeyIds, boolean exportSecret) {
- Log.d(Constants.TAG, "exportKeys started");
- mExportSecret = exportSecret;
- mMasterKeyIds = masterKeyIds; // if masterKeyIds is null it means export all
-
- CryptoOperationHelper<ExportKeyringParcel, ExportResult> exportOpHelper =
- new CryptoOperationHelper<>(1, mActivity, this, R.string.progress_exporting);
- exportOpHelper.cryptoOperation();
- }
-
- @Override
- public ExportKeyringParcel createOperationInput() {
- return new ExportKeyringParcel(mMasterKeyIds, mExportSecret, mExportFile.getAbsolutePath());
- }
-
- @Override
- final public void onCryptoOperationSuccess(ExportResult result) {
- // trigger scan of the created 'media' file so it shows up on MTP
- // http://stackoverflow.com/questions/13737261/nexus-4-not-showing-files-via-mtp
- mActivity.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(mExportFile)));
- result.createNotify(mActivity).show();
- }
-
- @Override
- public void onCryptoOperationCancelled() {
-
- }
-
- @Override
- public void onCryptoOperationError(ExportResult result) {
- result.createNotify(mActivity).show();
- }
-
- @Override
- public boolean onCryptoSetProgress(String msg, int progress, int max) {
- return false;
- }
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java
index 9fb362412..bae119700 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java
@@ -17,8 +17,20 @@
package org.sufficientlysecure.keychain.util;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.SecureRandom;
+import java.text.DecimalFormat;
+
import android.annotation.TargetApi;
-import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Context;
@@ -30,30 +42,12 @@ import android.net.Uri;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Environment;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
import android.provider.DocumentsContract;
import android.provider.OpenableColumns;
-import android.support.annotation.StringRes;
import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
import android.widget.Toast;
-import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
-import org.sufficientlysecure.keychain.ui.dialog.FileDialogFragment;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.text.DecimalFormat;
-
/** This class offers a number of helper functions for saving documents.
*
@@ -81,53 +75,31 @@ import java.text.DecimalFormat;
*/
public class FileHelper {
- public static void openDocument(Fragment fragment, Uri last, String mimeType, boolean multiple, int requestCode) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
- openDocumentPreKitKat(fragment, last, mimeType, multiple, requestCode);
- } else {
- openDocumentKitKat(fragment, mimeType, multiple, requestCode);
- }
+ @TargetApi(VERSION_CODES.KITKAT)
+ public static void saveDocument(Fragment fragment, String targetName, int requestCode) {
+ saveDocument(fragment, targetName, "*/*", requestCode);
}
- public static void saveDocument(Fragment fragment, String targetName, Uri inputUri,
- @StringRes int title, @StringRes int message, int requestCode) {
- saveDocument(fragment, targetName, inputUri, "*/*", title, message, requestCode);
+ /** Opens the storage browser on Android 4.4 or later for saving a file. */
+ @TargetApi(VERSION_CODES.KITKAT)
+ public static void saveDocument(Fragment fragment, String suggestedName, String mimeType, int requestCode) {
+ Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType(mimeType);
+ // Note: This is not documented, but works: Show the Internal Storage menu item in the drawer!
+ intent.putExtra("android.content.extra.SHOW_ADVANCED", true);
+ intent.putExtra(Intent.EXTRA_TITLE, suggestedName);
+ fragment.startActivityForResult(intent, requestCode);
}
- public static void saveDocument(Fragment fragment, String targetName, Uri inputUri, String mimeType,
- @StringRes int title, @StringRes int message, int requestCode) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
- saveDocumentDialog(fragment, targetName, inputUri, title, message, requestCode);
+ public static void openDocument(Fragment fragment, Uri last, String mimeType, boolean multiple, int requestCode) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ openDocumentKitKat(fragment, mimeType, multiple, requestCode);
} else {
- saveDocumentKitKat(fragment, mimeType, targetName, requestCode);
+ openDocumentPreKitKat(fragment, last, mimeType, multiple, requestCode);
}
}
- public static void saveDocumentDialog(final Fragment fragment, String targetName, Uri inputUri,
- @StringRes int title, @StringRes int message, final int requestCode) {
-
- saveDocumentDialog(fragment, targetName, inputUri, title, message, new FileDialogCallback() {
- // is this a good idea? seems hacky...
- @Override
- public void onFileSelected(File file, boolean checked) {
- Intent intent = new Intent();
- intent.setData(Uri.fromFile(file));
- fragment.onActivityResult(requestCode, Activity.RESULT_OK, intent);
- }
- });
- }
-
- public static void saveDocumentDialog(final Fragment fragment, String targetName, Uri inputUri,
- @StringRes int title, @StringRes int message, FileDialogCallback callback) {
-
- File file = inputUri == null ? null : new File(inputUri.getPath());
- File parentDir = file != null && file.exists() ? file.getParentFile() : Constants.Path.APP_DIR;
- File targetFile = new File(parentDir, targetName);
- saveDocumentDialog(callback, fragment.getActivity().getSupportFragmentManager(),
- fragment.getString(title), fragment.getString(message), targetFile, null);
-
- }
-
/** Opens the preferred installed file manager on Android and shows a toast
* if no manager is installed. */
private static void openDocumentPreKitKat(
@@ -157,51 +129,12 @@ public class FileHelper {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType(mimeType);
+ // Note: This is not documented, but works: Show the Internal Storage menu item in the drawer!
+ intent.putExtra("android.content.extra.SHOW_ADVANCED", true);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, multiple);
fragment.startActivityForResult(intent, requestCode);
}
- /** Opens the storage browser on Android 4.4 or later for saving a file. */
- @TargetApi(Build.VERSION_CODES.KITKAT)
- public static void saveDocumentKitKat(Fragment fragment, String mimeType, String suggestedName, int requestCode) {
- Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- intent.setType(mimeType);
- intent.putExtra("android.content.extra.SHOW_ADVANCED", true); // Note: This is not documented, but works
- intent.putExtra(Intent.EXTRA_TITLE, suggestedName);
- fragment.startActivityForResult(intent, requestCode);
- }
-
- public static void saveDocumentDialog(
- final FileDialogCallback callback, final FragmentManager fragmentManager,
- final String title, final String message, final File defaultFile,
- final String checkMsg) {
- // Message is received after file is selected
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.what == FileDialogFragment.MESSAGE_OKAY) {
- callback.onFileSelected(
- new File(message.getData().getString(FileDialogFragment.MESSAGE_DATA_FILE)),
- message.getData().getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED));
- }
- }
- };
-
- // Create a new Messenger for the communication back
- final Messenger messenger = new Messenger(returnHandler);
-
- DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
- @Override
- public void run() {
- FileDialogFragment fileDialog = FileDialogFragment.newInstance(messenger, title, message,
- defaultFile, checkMsg);
-
- fileDialog.show(fragmentManager, "fileDialog");
- }
- });
- }
-
public static String getFilename(Context context, Uri uri) {
String filename = null;
try {
@@ -228,6 +161,14 @@ public class FileHelper {
}
public static long getFileSize(Context context, Uri uri, long def) {
+ if ("file".equals(uri.getScheme())) {
+ long size = new File(uri.getPath()).length();
+ if (size == 0) {
+ size = def;
+ }
+ return size;
+ }
+
long size = def;
try {
Cursor cursor = context.getContentResolver().query(uri, new String[]{OpenableColumns.SIZE}, null, null, null);
@@ -322,6 +263,44 @@ public class FileHelper {
}
}
+ /**
+ * Deletes data at a URI securely by overwriting it with random data
+ * before deleting it. This method is fail-fast - if we can't securely
+ * delete the file, we don't delete it at all.
+ */
+ public static int deleteFileSecurely(Context context, Uri uri)
+ throws IOException {
+
+ ContentResolver resolver = context.getContentResolver();
+ long lengthLeft = FileHelper.getFileSize(context, uri);
+
+ if (lengthLeft == -1) {
+ throw new IOException("Error opening file!");
+ }
+
+ SecureRandom random = new SecureRandom();
+ byte[] randomData = new byte[1024];
+
+ OutputStream out = resolver.openOutputStream(uri, "w");
+ if (out == null) {
+ throw new IOException("Error opening file!");
+ }
+ out = new BufferedOutputStream(out);
+ while (lengthLeft > 0) {
+ random.nextBytes(randomData);
+ out.write(randomData, 0, lengthLeft > randomData.length ? randomData.length : (int) lengthLeft);
+ lengthLeft -= randomData.length;
+ }
+ out.close();
+
+ if ("file".equals(uri.getScheme())) {
+ return new File(uri.getPath()).delete() ? 1 : 0;
+ } else {
+ return resolver.delete(uri, null, null);
+ }
+
+ }
+
/** Checks if external storage is mounted if file is located on external storage. */
public static boolean isStorageMounted(String file) {
if (file.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
@@ -333,7 +312,24 @@ public class FileHelper {
return true;
}
- public interface FileDialogCallback {
- void onFileSelected(File file, boolean checked);
+ /** A replacement for ContentResolver.openInputStream() that does not allow
+ * the usage of "file" Uris that point to private files owned by the
+ * application only, *on Lollipop devices*.
+ *
+ * The check will be performed on devices >= Lollipop only, which have the
+ * necessary API to stat filedescriptors.
+ *
+ * @see FileHelperLollipop
+ */
+ public static InputStream openInputStreamSafe(ContentResolver resolver, Uri uri)
+ throws FileNotFoundException {
+
+ // Not supported on Android < 5
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
+ return FileHelperLollipop.openInputStreamSafe(resolver, uri);
+ } else {
+ return resolver.openInputStream(uri);
+ }
}
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelperLollipop.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelperLollipop.java
new file mode 100644
index 000000000..f89d679bc
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelperLollipop.java
@@ -0,0 +1,82 @@
+package org.sufficientlysecure.keychain.util;
+
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.annotation.TargetApi;
+import android.content.ContentResolver;
+import android.content.res.AssetFileDescriptor;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
+
+import org.sufficientlysecure.keychain.Constants;
+
+import static android.system.OsConstants.S_IROTH;
+
+
+/** FileHelper methods which use Lollipop-exclusive API.
+ * Some of the methods and static fields used here cause VerifyErrors because
+ * they do not exist in pre-lollipop API, so they must be kept in a
+ * lollipop-only class. All methods here should only be called by FileHelper,
+ * and consequently have package visibility.
+ */
+@TargetApi(VERSION_CODES.LOLLIPOP)
+class FileHelperLollipop {
+ /**
+ * Tests whether a file is readable by others
+ */
+ private static boolean S_IROTH(int mode) {
+ return (mode & S_IROTH) == S_IROTH;
+ }
+
+ /**
+ * A replacement for ContentResolver.openInputStream() that does not allow the usage of
+ * "file" Uris that point to private files owned by the application only.
+ *
+ * This is not allowed:
+ * am start -a android.intent.action.SEND -t text/plain -n
+ * "org.sufficientlysecure.keychain.debug/org.sufficientlysecure.keychain.ui.EncryptFilesActivity" --eu
+ * android.intent.extra.STREAM
+ * file:///data/data/org.sufficientlysecure.keychain.debug/databases/openkeychain.db
+ *
+ * @throws FileNotFoundException
+ */
+ static InputStream openInputStreamSafe(ContentResolver resolver, Uri uri)
+ throws FileNotFoundException {
+
+ String scheme = uri.getScheme();
+ if (ContentResolver.SCHEME_FILE.equals(scheme)) {
+ ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+ new File(uri.getPath()), ParcelFileDescriptor.parseMode("r"));
+
+ try {
+ final StructStat st = Os.fstat(pfd.getFileDescriptor());
+ if (!S_IROTH(st.st_mode)) {
+ Log.e(Constants.TAG, "File is not readable by others, aborting!");
+ throw new FileNotFoundException("Unable to create stream");
+ }
+ } catch (ErrnoException e) {
+ Log.e(Constants.TAG, "fstat() failed: " + e);
+ throw new FileNotFoundException("fstat() failed");
+ }
+
+ AssetFileDescriptor fd = new AssetFileDescriptor(pfd, 0, -1);
+ try {
+ return fd.createInputStream();
+ } catch (IOException e) {
+ throw new FileNotFoundException("Unable to create stream");
+ }
+ } else {
+ return resolver.openInputStream(uri);
+ }
+
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FilterCursorWrapper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FilterCursorWrapper.java
index ab73f59b8..d06f2ab65 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FilterCursorWrapper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FilterCursorWrapper.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
package org.sufficientlysecure.keychain.util;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java
index 2b47fd623..af4e0d4f8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java
@@ -98,7 +98,7 @@ public class NfcHelper {
* guarantee that this activity starts when receiving a beamed message. For now, this code
* uses the tag dispatch system.
*/
- return new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME,
+ return new NdefMessage(NdefRecord.createMime(Constants.MIME_TYPE_KEYS,
mNfcKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME));
}
};
@@ -141,6 +141,10 @@ public class NfcHelper {
}
protected void onPostExecute(Void unused) {
+ if (mActivity.isFinishing()) {
+ return;
+ }
+
// Register callback to set NDEF message
mNfcAdapter.setNdefPushMessageCallback(mNdefCallback,
mActivity);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/OkHttpKeybaseClient.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/OkHttpKeybaseClient.java
new file mode 100644
index 000000000..d2c90cfcd
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/OkHttpKeybaseClient.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.util;
+
+import com.squareup.okhttp.OkHttpClient;
+import com.squareup.okhttp.OkUrlFactory;
+import com.textuality.keybase.lib.KeybaseUrlConnectionClient;
+
+import org.sufficientlysecure.keychain.Constants;
+
+import java.io.IOException;
+import java.net.Proxy;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Wrapper for Keybase Lib
+ */
+public class OkHttpKeybaseClient implements KeybaseUrlConnectionClient {
+
+ private OkUrlFactory generateUrlFactory() {
+ OkHttpClient client = new OkHttpClient();
+ return new OkUrlFactory(client);
+ }
+
+ @Override
+ public URLConnection openConnection(URL url, Proxy proxy, boolean isKeybase) throws IOException {
+ OkUrlFactory factory = generateUrlFactory();
+ if (proxy != null) {
+ factory.client().setProxy(proxy);
+ factory.client().setConnectTimeout(30000, TimeUnit.MILLISECONDS);
+ factory.client().setReadTimeout(40000, TimeUnit.MILLISECONDS);
+ } else {
+ factory.client().setConnectTimeout(5000, TimeUnit.MILLISECONDS);
+ factory.client().setReadTimeout(25000, TimeUnit.MILLISECONDS);
+ }
+
+ factory.client().setFollowSslRedirects(false);
+
+ // forced the usage of api.keybase.io pinned certificate
+ if (isKeybase) {
+ try {
+ if (!TlsHelper.usePinnedCertificateIfAvailable(factory.client(), url)) {
+ throw new IOException("no pinned certificate found for URL!");
+ }
+ } catch (TlsHelper.TlsHelperException e) {
+ Log.e(Constants.TAG, "TlsHelper failed", e);
+ throw new IOException("TlsHelper failed");
+ }
+ }
+
+ return factory.open(url);
+ }
+
+ @Override
+ public String getKeybaseBaseUrl() {
+ return "https://api.keybase.io/";
+ }
+
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableProxy.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableProxy.java
index 7e788d04c..7e2328e99 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableProxy.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableProxy.java
@@ -17,12 +17,14 @@
package org.sufficientlysecure.keychain.util;
-import android.os.Parcel;
-import android.os.Parcelable;
import java.net.InetSocketAddress;
import java.net.Proxy;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+
/**
* used to simply transport java.net.Proxy objects created using InetSockets between services/activities
*/
@@ -47,9 +49,10 @@ public class ParcelableProxy implements Parcelable {
return new ParcelableProxy(null, -1, null);
}
+ @NonNull
public Proxy getProxy() {
if (mProxyHost == null) {
- return null;
+ return Proxy.NO_PROXY;
}
/*
* InetSocketAddress.createUnresolved so we can use this method even in the main thread
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java
index 4ef215036..559c5556f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java
@@ -23,6 +23,9 @@ import android.content.SharedPreferences;
import android.content.res.Resources;
import android.preference.PreferenceManager;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Constants.Pref;
import org.sufficientlysecure.keychain.service.KeyserverSyncAdapterService;
@@ -123,16 +126,6 @@ public class Preferences {
return mSharedPreferences.getBoolean(Constants.Pref.FIRST_TIME, true);
}
- public boolean useDefaultYubiKeyPin() {
- return mSharedPreferences.getBoolean(Pref.USE_DEFAULT_YUBIKEY_PIN, false);
- }
-
- public void setUseDefaultYubiKeyPin(boolean useDefaultYubikeyPin) {
- SharedPreferences.Editor editor = mSharedPreferences.edit();
- editor.putBoolean(Pref.USE_DEFAULT_YUBIKEY_PIN, useDefaultYubikeyPin);
- editor.commit();
- }
-
public boolean useNumKeypadForYubiKeyPin() {
return mSharedPreferences.getBoolean(Pref.USE_NUMKEYPAD_FOR_YUBIKEY_PIN, true);
}
@@ -332,6 +325,12 @@ public class Preferences {
if (!torEnabled && !normalPorxyEnabled) this.parcelableProxy = new ParcelableProxy(null, -1, null);
else this.parcelableProxy = new ParcelableProxy(hostName, port, type);
}
+
+ @NonNull
+ public Proxy getProxy() {
+ return parcelableProxy.getProxy();
+ }
+
}
// cloud prefs
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java
deleted file mode 100644
index 0297d149c..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.util;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.LabeledIntent;
-import android.content.pm.ResolveInfo;
-import android.os.Build;
-import android.os.Parcelable;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-public class ShareHelper {
- Context mContext;
-
- public ShareHelper(Context context) {
- mContext = context;
- }
-
- /**
- * Create Intent Chooser but exclude specific activites, e.g., EncryptActivity to prevent encrypting again
- * <p/>
- * Put together from some stackoverflow posts...
- */
- public Intent createChooserExcluding(Intent prototype, String title, String[] activityBlacklist) {
- // Produced an empty list on Huawei U8860 with Android Version 4.0.3
- // TODO: test on 4.1, 4.2, 4.3, only tested on 4.4
- // Disabled on 5.0 because using EXTRA_INITIAL_INTENTS prevents the usage based sorting
- // introduced in 5.0: https://medium.com/@xXxXxXxXxXam/how-lollipops-share-menu-is-organized-d204888f606d
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- return Intent.createChooser(prototype, title);
- }
-
- List<LabeledIntent> targetedShareIntents = new ArrayList<>();
-
- List<ResolveInfo> resInfoList = mContext.getPackageManager().queryIntentActivities(prototype, 0);
- List<ResolveInfo> resInfoListFiltered = new ArrayList<>();
- if (!resInfoList.isEmpty()) {
- for (ResolveInfo resolveInfo : resInfoList) {
- // do not add blacklisted ones
- if (resolveInfo.activityInfo == null || Arrays.asList(activityBlacklist).contains(resolveInfo.activityInfo.name))
- continue;
-
- resInfoListFiltered.add(resolveInfo);
- }
-
- if (!resInfoListFiltered.isEmpty()) {
- // sorting for nice readability
- Collections.sort(resInfoListFiltered, new Comparator<ResolveInfo>() {
- @Override
- public int compare(ResolveInfo first, ResolveInfo second) {
- String firstName = first.loadLabel(mContext.getPackageManager()).toString();
- String secondName = second.loadLabel(mContext.getPackageManager()).toString();
- return firstName.compareToIgnoreCase(secondName);
- }
- });
-
- // create the custom intent list
- for (ResolveInfo resolveInfo : resInfoListFiltered) {
- Intent targetedShareIntent = (Intent) prototype.clone();
- targetedShareIntent.setPackage(resolveInfo.activityInfo.packageName);
- targetedShareIntent.setClassName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name);
-
- LabeledIntent lIntent = new LabeledIntent(targetedShareIntent,
- resolveInfo.activityInfo.packageName,
- resolveInfo.loadLabel(mContext.getPackageManager()),
- resolveInfo.activityInfo.icon);
- targetedShareIntents.add(lIntent);
- }
-
- // Create chooser with only one Intent in it
- Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(targetedShareIntents.size() - 1), title);
- // append all other Intents
- // TODO this line looks wrong?!
- chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[]{}));
- return chooserIntent;
- }
-
- }
-
- // fallback to Android's default chooser
- return Intent.createChooser(prototype, title);
- }
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java
index d1d1ada2a..1492abdeb 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2013-2015 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.util;
import android.content.res.AssetManager;
import com.squareup.okhttp.OkHttpClient;
+
import org.sufficientlysecure.keychain.Constants;
import java.io.ByteArrayInputStream;
@@ -37,7 +38,6 @@ import java.security.cert.CertificateFactory;
import java.util.HashMap;
import java.util.Map;
-import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
@@ -49,15 +49,14 @@ public class TlsHelper {
}
}
- private static Map<String, byte[]> sStaticCA = new HashMap<>();
-
- public static void addStaticCA(String domain, byte[] certificate) {
- sStaticCA.put(domain, certificate);
- }
+ private static Map<String, byte[]> sPinnedCertificates = new HashMap<>();
- public static void addStaticCA(String domain, AssetManager assetManager, String name) {
+ /**
+ * Add certificate from assets to pinned certificate map.
+ */
+ public static void addPinnedCertificate(String host, AssetManager assetManager, String cerFilename) {
try {
- InputStream is = assetManager.open(name);
+ InputStream is = assetManager.open(cerFilename);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int reads = is.read();
@@ -68,27 +67,36 @@ public class TlsHelper {
is.close();
- addStaticCA(domain, baos.toByteArray());
+ sPinnedCertificates.put(host, baos.toByteArray());
} catch (IOException e) {
Log.w(Constants.TAG, e);
}
}
- public static void pinCertificateIfNecessary(OkHttpClient client, URL url) throws TlsHelperException, IOException {
+ /**
+ * Use pinned certificate for OkHttpClient if we have one.
+ *
+ * @return true, if certificate is available, false if not
+ * @throws TlsHelperException
+ * @throws IOException
+ */
+ public static boolean usePinnedCertificateIfAvailable(OkHttpClient client, URL url) throws TlsHelperException, IOException {
if (url.getProtocol().equals("https")) {
- for (String domain : sStaticCA.keySet()) {
- if (url.getHost().endsWith(domain)) {
- pinCertificate(sStaticCA.get(domain), client);
+ // use certificate PIN from assets if we have one
+ for (String host : sPinnedCertificates.keySet()) {
+ if (url.getHost().endsWith(host)) {
+ pinCertificate(sPinnedCertificates.get(host), client);
+ return true;
}
}
}
+ return false;
}
/**
* Modifies the client to accept only requests with a given certificate. Applies to all URLs requested by the
* client.
* Therefore a client that is pinned this way should be used to only make requests to URLs with passed certificate.
- * TODO: Refactor - More like SSH StrictHostKeyChecking than pinning?
*
* @param certificate certificate to pin
* @param client OkHttpClient to enforce pinning on
@@ -97,8 +105,10 @@ public class TlsHelper {
*/
private static void pinCertificate(byte[] certificate, OkHttpClient client)
throws TlsHelperException, IOException {
- // We don't use OkHttp's CertificatePinner since it depends on a TrustManager to verify it too. Refer to
- // note at end of description: http://square.github.io/okhttp/javadoc/com/squareup/okhttp/CertificatePinner.html
+ // We don't use OkHttp's CertificatePinner since it can not be used to pin self-signed
+ // certificate if such certificate is not accepted by TrustManager.
+ // (Refer to note at end of description:
+ // http://square.github.io/okhttp/javadoc/com/squareup/okhttp/CertificatePinner.html )
// Creating our own TrustManager that trusts only our certificate eliminates the need for certificate pinning
try {
// Load CA
@@ -126,42 +136,4 @@ public class TlsHelper {
}
}
- /**
- * Opens a Connection that will only accept certificates signed with a specific CA and skips common name check.
- * This is required for some distributed Keyserver networks like sks-keyservers.net
- *
- * @param certificate The X.509 certificate used to sign the servers certificate
- * @param url Connection target
- */
- public static HttpsURLConnection openCAConnection(byte[] certificate, URL url)
- throws TlsHelperException, IOException {
- try {
- // Load CA
- CertificateFactory cf = CertificateFactory.getInstance("X.509");
- Certificate ca = cf.generateCertificate(new ByteArrayInputStream(certificate));
-
- // Create a KeyStore containing our trusted CAs
- String keyStoreType = KeyStore.getDefaultType();
- KeyStore keyStore = KeyStore.getInstance(keyStoreType);
- keyStore.load(null, null);
- keyStore.setCertificateEntry("ca", ca);
-
- // Create a TrustManager that trusts the CAs in our KeyStore
- String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
- tmf.init(keyStore);
-
- // Create an SSLContext that uses our TrustManager
- SSLContext context = SSLContext.getInstance("TLS");
- context.init(null, tmf.getTrustManagers(), null);
-
- // Tell the URLConnection to use a SocketFactory from our SSLContext
- HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
- urlConnection.setSSLSocketFactory(context.getSocketFactory());
-
- return urlConnection;
- } catch (CertificateException | KeyManagementException | KeyStoreException | NoSuchAlgorithmException e) {
- throw new TlsHelperException(e);
- }
- }
}
diff --git a/OpenKeychain/src/main/res/anim/fade_in_delayed.xml b/OpenKeychain/src/main/res/anim/fade_in_delayed.xml
new file mode 100644
index 000000000..3f2887b5e
--- /dev/null
+++ b/OpenKeychain/src/main/res/anim/fade_in_delayed.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:interpolator="@android:anim/bounce_interpolator"
+ android:duration="700"
+ android:startOffset="400"
+ />
+</set>
diff --git a/OpenKeychain/src/main/res/anim/fade_out_delayed.xml b/OpenKeychain/src/main/res/anim/fade_out_delayed.xml
new file mode 100644
index 000000000..a895bdedd
--- /dev/null
+++ b/OpenKeychain/src/main/res/anim/fade_out_delayed.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:interpolator="@android:anim/accelerate_interpolator"
+ android:duration="300"
+ android:startOffset="400"
+ />
+</set>
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_action_encrypt_paste_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_encrypt_paste_24dp.png
new file mode 100644
index 000000000..356cfbe43
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_action_encrypt_paste_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_check_black_24dp.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_check_black_24dp.png
new file mode 100644
index 000000000..e802d90ae
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-hdpi/ic_check_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_action_encrypt_paste_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_encrypt_paste_24dp.png
new file mode 100644
index 000000000..a546e152b
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_action_encrypt_paste_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_check_black_24dp.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_check_black_24dp.png
new file mode 100644
index 000000000..1c14c9c44
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-mdpi/ic_check_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_encrypt_paste_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_encrypt_paste_24dp.png
new file mode 100644
index 000000000..ed7fdb732
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_action_encrypt_paste_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_black_24dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_black_24dp.png
new file mode 100644
index 000000000..64a4944f7
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/ic_check_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_expired_cutout_96dp.png b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_expired_cutout_96dp.png
index e69de29bb..568b48c43 100644
--- a/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_expired_cutout_96dp.png
+++ b/OpenKeychain/src/main/res/drawable-xhdpi/status_signature_expired_cutout_96dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_encrypt_paste_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_encrypt_paste_24dp.png
new file mode 100644
index 000000000..50987bdd6
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_action_encrypt_paste_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_black_24dp.png
new file mode 100644
index 000000000..b26a2c05e
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_check_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_action_encrypt_paste_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_action_encrypt_paste_24dp.png
new file mode 100644
index 000000000..11ad7e219
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_action_encrypt_paste_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_black_24dp.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_black_24dp.png
new file mode 100644
index 000000000..2f6d6386d
--- /dev/null
+++ b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_check_black_24dp.png
Binary files differ
diff --git a/OpenKeychain/src/main/res/layout-land/backup_code_fragment.xml b/OpenKeychain/src/main/res/layout-land/backup_code_fragment.xml
new file mode 100644
index 000000000..3157bbfd3
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout-land/backup_code_fragment.xml
@@ -0,0 +1,343 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingTop="20dp">
+
+ <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
+ android:id="@+id/title_animator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:inAnimation="@anim/fade_in"
+ android:outAnimation="@anim/fade_out"
+ custom:initialView="0">
+
+ <TextView
+ style="?android:textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:padding="10dp"
+ android:text="@string/backup_code_explanation" />
+
+ <TextView
+ style="?android:textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:padding="10dp"
+ android:text="@string/backup_code_enter" />
+
+ <TextView
+ style="?android:textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:padding="10dp"
+ android:text="@string/backup_code_ok" />
+
+ </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
+
+ <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
+ android:id="@+id/code_animator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginBottom="15dp"
+ android:layout_marginTop="15dp"
+ android:inAnimation="@anim/fade_in"
+ android:outAnimation="@anim/fade_out"
+ custom:initialView="1">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal">
+
+ <TextView
+ android:id="@+id/backup_code_display_1"
+ style="@android:style/Widget.EditText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:clickable="false"
+ android:focusable="false"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="SpUsage"
+ tools:text="ABCDEF" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:id="@+id/backup_code_display_2"
+ style="@android:style/Widget.EditText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:clickable="false"
+ android:focusable="false"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="SpUsage"
+ tools:text="GHIJKL" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:id="@+id/backup_code_display_3"
+ style="@android:style/Widget.EditText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:clickable="false"
+ android:focusable="false"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="SpUsage"
+ tools:text="MNOPQR" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:id="@+id/backup_code_display_4"
+ style="@android:style/Widget.EditText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:clickable="false"
+ android:focusable="false"
+ android:singleLine="true"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="SpUsage"
+ tools:text="STUVWX" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal">
+
+ <!--
+ The most reliable way to correctly size these I found was to put a transparent hint on them.
+ Theoretically, this should be what the android:ems attribute is for - didn't work for me.
+ -->
+ <EditText
+ android:id="@+id/backup_code_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <EditText
+ android:id="@+id/backup_code_2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <EditText
+ android:id="@+id/backup_code_3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <EditText
+ android:id="@+id/backup_code_4"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ </LinearLayout>
+
+ </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
+
+ <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
+ android:id="@+id/status_animator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:inAnimation="@anim/fade_in_delayed"
+ android:outAnimation="@anim/fade_out"
+ custom:initialView="2">
+
+ <Button
+ android:id="@+id/button_backup_input"
+ style="?android:buttonBarButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_margin="10dp"
+ android:drawableLeft="@drawable/ic_mode_edit_grey_24dp"
+ android:drawablePadding="8dp"
+ android:padding="12dp"
+ android:text="@string/btn_code_wrotedown" />
+
+ <Space
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:orientation="horizontal">
+
+ <TextView
+ style="?android:textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:text="@string/backup_code_wrong" />
+
+ <Button
+ android:id="@+id/button_backup_back"
+ style="?android:buttonBarButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_margin="10dp"
+ android:drawableLeft="@drawable/ic_repeat_grey_24dp"
+ android:drawablePadding="8dp"
+ android:padding="12dp"
+ android:text="@string/btn_backup_back" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ style="?android:buttonBarStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal">
+
+ <Button
+ android:id="@+id/button_backup_share"
+ style="?android:buttonBarButtonStyle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:layout_weight="1"
+ android:drawableLeft="@drawable/ic_share_grey_24dp"
+ android:drawablePadding="8dp"
+ android:padding="12dp"
+ android:text="@string/btn_backup_share" />
+
+ <Button
+ android:id="@+id/button_backup_save"
+ style="?android:buttonBarButtonStyle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:layout_weight="1"
+ android:drawableLeft="@drawable/ic_save_grey_24dp"
+ android:drawablePadding="8dp"
+ android:padding="12dp"
+ android:text="@string/btn_backup_save" />
+
+ </LinearLayout>
+
+ </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
+
+
+</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout-land/qr_code_activity.xml b/OpenKeychain/src/main/res/layout-land/qr_code_activity.xml
deleted file mode 100644
index 59a733e89..000000000
--- a/OpenKeychain/src/main/res/layout-land/qr_code_activity.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <include
- android:id="@+id/toolbar_include"
- layout="@layout/toolbar_standalone" />
-
- <LinearLayout
- android:layout_below="@id/toolbar_include"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.CardView
- android:id="@+id/qr_code_image_layout"
- android:transitionName="qr_code"
- android:layout_gravity="center_horizontal"
- android:layout_margin="32dp"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:clickable="true"
- android:foreground="?android:attr/selectableItemBackground"
- app:cardBackgroundColor="@android:color/white"
- app:cardUseCompatPadding="true"
- app:cardCornerRadius="4dp">
-
- <org.sufficientlysecure.keychain.ui.widget.AspectRatioImageView
- android:id="@+id/qr_code_image"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- app:dominantMeasurement="height"
- app:aspectRatioEnabled="true" />
- </android.support.v7.widget.CardView>
-
- </LinearLayout>
-</RelativeLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout-mdpi/backup_code_fragment.xml b/OpenKeychain/src/main/res/layout-mdpi/backup_code_fragment.xml
new file mode 100644
index 000000000..2e2159f4e
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout-mdpi/backup_code_fragment.xml
@@ -0,0 +1,343 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingTop="50dp">
+
+ <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
+ android:id="@+id/title_animator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:inAnimation="@anim/fade_in"
+ android:outAnimation="@anim/fade_out"
+ custom:initialView="0">
+
+ <TextView
+ style="?android:textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:padding="10dp"
+ android:text="@string/backup_code_explanation" />
+
+ <TextView
+ style="?android:textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:padding="10dp"
+ android:text="@string/backup_code_enter" />
+
+ <TextView
+ style="?android:textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:padding="10dp"
+ android:text="@string/backup_code_ok" />
+
+ </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
+
+ <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
+ android:id="@+id/code_animator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginBottom="15dp"
+ android:layout_marginTop="15dp"
+ android:inAnimation="@anim/fade_in"
+ android:outAnimation="@anim/fade_out"
+ custom:initialView="0">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal">
+
+ <TextView
+ android:id="@+id/backup_code_display_1"
+ style="@android:style/Widget.EditText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:clickable="false"
+ android:focusable="false"
+ android:textSize="16dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="SpUsage"
+ tools:text="ABCDEF" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="16dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:id="@+id/backup_code_display_2"
+ style="@android:style/Widget.EditText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:clickable="false"
+ android:focusable="false"
+ android:textSize="16dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="SpUsage"
+ tools:text="GHIJKL" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="16dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:id="@+id/backup_code_display_3"
+ style="@android:style/Widget.EditText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:clickable="false"
+ android:focusable="false"
+ android:textSize="16dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="SpUsage"
+ tools:text="MNOPQR" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="16dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:id="@+id/backup_code_display_4"
+ style="@android:style/Widget.EditText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:clickable="false"
+ android:focusable="false"
+ android:singleLine="true"
+ android:textSize="16dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="SpUsage"
+ tools:text="STUVWX" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal">
+
+ <!--
+ The most reliable way to correctly size these I found was to put a transparent hint on them.
+ Theoretically, this should be what the android:ems attribute is for - didn't work for me.
+ -->
+ <EditText
+ android:id="@+id/backup_code_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="16dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="16dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <EditText
+ android:id="@+id/backup_code_2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="16dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="16dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <EditText
+ android:id="@+id/backup_code_3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="16dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="16dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <EditText
+ android:id="@+id/backup_code_4"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="16dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ </LinearLayout>
+
+ </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
+
+ <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
+ android:id="@+id/status_animator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:inAnimation="@anim/fade_in_delayed"
+ android:outAnimation="@anim/fade_out"
+ custom:initialView="2">
+
+ <Button
+ android:id="@+id/button_backup_input"
+ style="?android:buttonBarButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_margin="10dp"
+ android:drawableLeft="@drawable/ic_mode_edit_grey_24dp"
+ android:drawablePadding="8dp"
+ android:padding="12dp"
+ android:text="@string/btn_code_wrotedown" />
+
+ <Space
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:orientation="vertical">
+
+ <TextView
+ style="?android:textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:text="@string/backup_code_wrong" />
+
+ <Button
+ android:id="@+id/button_backup_back"
+ style="?android:buttonBarButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_margin="10dp"
+ android:drawableLeft="@drawable/ic_repeat_grey_24dp"
+ android:drawablePadding="8dp"
+ android:padding="12dp"
+ android:text="@string/btn_backup_back" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ style="?android:buttonBarStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal">
+
+ <Button
+ android:id="@+id/button_backup_share"
+ style="?android:buttonBarButtonStyle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:layout_weight="1"
+ android:drawableLeft="@drawable/ic_share_grey_24dp"
+ android:drawablePadding="8dp"
+ android:padding="12dp"
+ android:text="@string/btn_backup_share" />
+
+ <Button
+ android:id="@+id/button_backup_save"
+ style="?android:buttonBarButtonStyle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:layout_weight="1"
+ android:drawableLeft="@drawable/ic_save_grey_24dp"
+ android:drawablePadding="8dp"
+ android:padding="12dp"
+ android:text="@string/btn_backup_save" />
+
+ </LinearLayout>
+
+ </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
+
+
+</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout-xhdpi/backup_code_fragment.xml b/OpenKeychain/src/main/res/layout-xhdpi/backup_code_fragment.xml
new file mode 100644
index 000000000..e7d8cac34
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout-xhdpi/backup_code_fragment.xml
@@ -0,0 +1,343 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingTop="50dp">
+
+ <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
+ android:id="@+id/title_animator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:inAnimation="@anim/fade_in"
+ android:outAnimation="@anim/fade_out"
+ custom:initialView="0">
+
+ <TextView
+ style="?android:textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:padding="10dp"
+ android:text="@string/backup_code_explanation" />
+
+ <TextView
+ style="?android:textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:padding="10dp"
+ android:text="@string/backup_code_enter" />
+
+ <TextView
+ style="?android:textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:padding="10dp"
+ android:text="@string/backup_code_ok" />
+
+ </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
+
+ <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
+ android:id="@+id/code_animator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginBottom="15dp"
+ android:layout_marginTop="15dp"
+ android:inAnimation="@anim/fade_in"
+ android:outAnimation="@anim/fade_out"
+ custom:initialView="0">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal">
+
+ <TextView
+ android:id="@+id/backup_code_display_1"
+ style="@android:style/Widget.EditText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:clickable="false"
+ android:focusable="false"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="SpUsage"
+ tools:text="ABCDEF" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:id="@+id/backup_code_display_2"
+ style="@android:style/Widget.EditText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:clickable="false"
+ android:focusable="false"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="SpUsage"
+ tools:text="GHIJKL" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:id="@+id/backup_code_display_3"
+ style="@android:style/Widget.EditText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:clickable="false"
+ android:focusable="false"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="SpUsage"
+ tools:text="MNOPQR" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:id="@+id/backup_code_display_4"
+ style="@android:style/Widget.EditText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:clickable="false"
+ android:focusable="false"
+ android:singleLine="true"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="SpUsage"
+ tools:text="STUVWX" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal">
+
+ <!--
+ The most reliable way to correctly size these I found was to put a transparent hint on them.
+ Theoretically, this should be what the android:ems attribute is for - didn't work for me.
+ -->
+ <EditText
+ android:id="@+id/backup_code_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <EditText
+ android:id="@+id/backup_code_2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <EditText
+ android:id="@+id/backup_code_3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <EditText
+ android:id="@+id/backup_code_4"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="18dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ </LinearLayout>
+
+ </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
+
+ <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
+ android:id="@+id/status_animator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:inAnimation="@anim/fade_in_delayed"
+ android:outAnimation="@anim/fade_out"
+ custom:initialView="2">
+
+ <Button
+ android:id="@+id/button_backup_input"
+ style="?android:buttonBarButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_margin="10dp"
+ android:drawableLeft="@drawable/ic_mode_edit_grey_24dp"
+ android:drawablePadding="8dp"
+ android:padding="12dp"
+ android:text="@string/btn_code_wrotedown" />
+
+ <Space
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:orientation="vertical">
+
+ <TextView
+ style="?android:textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:text="@string/backup_code_wrong" />
+
+ <Button
+ android:id="@+id/button_backup_back"
+ style="?android:buttonBarButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_margin="10dp"
+ android:drawableLeft="@drawable/ic_repeat_grey_24dp"
+ android:drawablePadding="8dp"
+ android:padding="12dp"
+ android:text="@string/btn_backup_back" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ style="?android:buttonBarStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal">
+
+ <Button
+ android:id="@+id/button_backup_share"
+ style="?android:buttonBarButtonStyle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:layout_weight="1"
+ android:drawableLeft="@drawable/ic_share_grey_24dp"
+ android:drawablePadding="8dp"
+ android:padding="12dp"
+ android:text="@string/btn_backup_share" />
+
+ <Button
+ android:id="@+id/button_backup_save"
+ style="?android:buttonBarButtonStyle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:layout_weight="1"
+ android:drawableLeft="@drawable/ic_save_grey_24dp"
+ android:drawablePadding="8dp"
+ android:padding="12dp"
+ android:text="@string/btn_backup_save" />
+
+ </LinearLayout>
+
+ </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
+
+
+</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml b/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml
index 78e9247ea..b83681537 100644
--- a/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml
+++ b/OpenKeychain/src/main/res/layout/add_keyserver_dialog.xml
@@ -9,21 +9,37 @@
android:paddingRight="24dp"
android:paddingTop="16dp">
- <EditText
- android:id="@+id/keyserver_url_edit_text"
+ <android.support.design.widget.TextInputLayout
+ android:id="@+id/keyserver_url_edit_text_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="8dp"
- android:ems="10"
- android:hint="@string/label_enter_keyserver_url"
- android:imeOptions="actionDone" />
+ android:layout_marginBottom="8dp">
+
+ <EditText
+ android:id="@+id/keyserver_url_edit_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:ems="10"
+ android:hint="@string/label_enter_keyserver_url"
+ android:imeOptions="actionDone"
+ android:inputType="textUri" />
+
+ </android.support.design.widget.TextInputLayout>
+
+
+ <CheckBox
+ android:id="@+id/verify_connection_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:text="@string/label_verify_keyserver_connection" />
<CheckBox
- android:id="@+id/verify_keyserver_checkbox"
+ android:id="@+id/only_trusted_keyserver_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/label_verify_keyserver"
- android:checked="true"/>
+ android:checked="true"
+ android:text="@string/label_only_trusted_keyserver" />
</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/backup_activity.xml b/OpenKeychain/src/main/res/layout/backup_activity.xml
new file mode 100644
index 000000000..59ab6cbf2
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/backup_activity.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <include
+ android:id="@+id/toolbar_include"
+ layout="@layout/toolbar_standalone_white" />
+
+ <LinearLayout
+ android:layout_below="@id/toolbar_include"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <include layout="@layout/notify_area" />
+
+ <FrameLayout
+ android:id="@+id/content_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ </FrameLayout>
+
+ </LinearLayout>
+</RelativeLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/backup_fragment.xml b/OpenKeychain/src/main/res/layout/backup_restore_fragment.xml
index 96fba954b..ce97b7fd4 100644
--- a/OpenKeychain/src/main/res/layout/backup_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/backup_restore_fragment.xml
@@ -61,6 +61,28 @@
android:text="@string/backup_public_keys"
android:textAppearance="?android:attr/textAppearanceMedium" />
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="@string/restore_section" />
+
+ <TextView
+ android:id="@+id/restore"
+ style="?android:attr/borderlessButtonStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:drawablePadding="8dp"
+ android:drawableRight="@drawable/ic_folder_grey_24dp"
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:text="@string/btn_decrypt_files"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
<View
android:layout_width="match_parent"
android:layout_height="1dip"
diff --git a/OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml b/OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml
index 239cdcc95..7e2f78531 100644
--- a/OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml
@@ -1,155 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <ScrollView
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_above="@+id/certify_fingerprint_buttons_divider">
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="16dp">
- <LinearLayout
+ <TextView
+ android:id="@+id/certify_fingerprint_intro"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="32dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:text="@string/certify_fingerprint_text"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <android.support.v7.widget.CardView
+ android:id="@+id/certify_fingerprint_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:padding="16dp">
+ android:layout_gravity="top"
+ app:cardBackgroundColor="?attr/colorCardViewBackground"
+ app:cardCornerRadius="4dp"
+ app:cardElevation="8dp"
+ app:cardUseCompatPadding="true">
- <TextView
- android:id="@+id/certify_fingerprint_intro"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@string/certify_fingerprint_text" />
+ android:orientation="vertical">
- <android.support.v7.widget.CardView
- android:id="@+id/certify_fingerprint_card"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- app:cardBackgroundColor="?attr/colorCardViewBackground"
- app:cardUseCompatPadding="true"
- app:cardCornerRadius="4dp"
- android:layout_gravity="top">
+ <TextView
+ android:id="@+id/certify_fingerprint_fingerprint_header"
+ style="@style/CardViewHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/label_fingerprint" />
- <LinearLayout
+ <TextView
+ android:id="@+id/certify_fingerprint_fingerprint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <TextView
- style="@style/CardViewHeader"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/label_fingerprint" />
-
- <TextView
- android:id="@+id/certify_fingerprint_fingerprint"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:textSize="20sp"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:typeface="monospace"
- android:gravity="center_vertical" />
- </LinearLayout>
-
- </android.support.v7.widget.CardView>
-
- </LinearLayout>
+ android:gravity="center_vertical"
+ android:paddingBottom="24dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingTop="16dp"
+ android:textSize="18sp"
+ android:typeface="monospace" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
- </ScrollView>
+ <TextView
+ android:id="@+id/certify_fingerprint_button_no"
+ style="?android:attr/borderlessButtonStyle"
+ android:textColor="@color/android_red_dark"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:clickable="true"
+ android:drawableLeft="@drawable/ic_close_black_24dp"
+ android:drawablePadding="8dp"
+ android:gravity="left|center_vertical"
+ android:minHeight="48dp"
+ android:text="@string/btn_not_matching"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+ <TextView
+ android:id="@+id/certify_fingerprint_button_yes"
+ style="?android:attr/borderlessButtonStyle"
+ android:textColor="@color/android_green_dark"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:layout_weight="1"
+ android:clickable="true"
+ android:drawableLeft="@drawable/ic_check_black_24dp"
+ android:drawablePadding="8dp"
+ android:gravity="left|center_vertical"
+ android:minHeight="48dp"
+ android:text="@string/btn_match"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_alignParentBottom="true"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp"
- android:id="@+id/certify_fingerprint_buttons">
+ </LinearLayout>
- <TextView
- android:id="@+id/certify_fingerprint_button_no"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/btn_no"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:gravity="center_vertical"
- android:clickable="true"
- style="?android:attr/borderlessButtonStyle"
- android:layout_gravity="center_vertical" />
- <View
- android:layout_width="1dp"
- android:layout_height="match_parent"
- android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp"
- android:background="?android:attr/listDivider" />
+ </android.support.v7.widget.CardView>
- <TextView
- android:id="@+id/certify_fingerprint_button_yes"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/btn_match"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:drawablePadding="8dp"
- android:gravity="center_vertical"
- android:clickable="true"
- style="?android:attr/borderlessButtonStyle"
- android:layout_gravity="center_vertical" />
</LinearLayout>
- <View
- android:id="@+id/certify_fingerprint_buttons_divider2"
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:background="?android:attr/listDivider"
- android:layout_alignBottom="@+id/certify_fingerprint_buttons_text"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true" />
-
- <TextView
- android:id="@+id/certify_fingerprint_buttons_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="24dp"
- android:layout_marginRight="24dp"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@string/certify_fingerprint_text2"
- android:layout_above="@+id/certify_fingerprint_buttons"
- android:layout_centerHorizontal="true" />
-
- <View
- android:id="@+id/certify_fingerprint_buttons_divider"
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:background="?android:attr/listDivider"
- android:layout_alignTop="@+id/certify_fingerprint_buttons_text"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true" />
-
-
-
-</RelativeLayout>
+</ScrollView>
diff --git a/OpenKeychain/src/main/res/layout/create_key_email_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_email_fragment.xml
index d4ece38ac..c1f692a88 100644
--- a/OpenKeychain/src/main/res/layout/create_key_email_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_key_email_fragment.xml
@@ -62,6 +62,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_gravity="center_vertical"
android:text="@string/btn_back"
android:textAllCaps="true"
android:minHeight="?android:attr/listPreferredItemHeight"
@@ -79,6 +80,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_gravity="center_vertical"
android:text="@string/btn_next"
android:textAllCaps="true"
android:minHeight="?android:attr/listPreferredItemHeight"
diff --git a/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml
index 9a6c33f82..118f0661a 100644
--- a/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_key_final_fragment.xml
@@ -155,6 +155,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_gravity="center_vertical"
android:text="@string/btn_back"
android:textAllCaps="true"
android:minHeight="?android:attr/listPreferredItemHeight"
@@ -172,6 +173,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_gravity="center_vertical"
android:text="@string/btn_create_key"
android:textAllCaps="true"
android:minHeight="?android:attr/listPreferredItemHeight"
diff --git a/OpenKeychain/src/main/res/layout/create_key_name_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_name_fragment.xml
index 7b8ba3fc1..4e37dd713 100644
--- a/OpenKeychain/src/main/res/layout/create_key_name_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_key_name_fragment.xml
@@ -56,6 +56,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_gravity="center_vertical"
android:text="@string/btn_back"
android:textAllCaps="true"
android:minHeight="?android:attr/listPreferredItemHeight"
@@ -73,6 +74,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_gravity="center_vertical"
android:text="@string/btn_next"
android:textAllCaps="true"
android:minHeight="?android:attr/listPreferredItemHeight"
diff --git a/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml
index 9d10bbe70..9368aa1ef 100644
--- a/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml
@@ -74,6 +74,7 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
android:layout_weight="1"
android:text="@string/btn_back"
android:textAllCaps="true"
@@ -91,6 +92,7 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
android:layout_weight="1"
android:text="@string/btn_next"
android:textAllCaps="true"
diff --git a/OpenKeychain/src/main/res/layout/create_key_start_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_start_fragment.xml
index 20c434c02..622cdf5a0 100644
--- a/OpenKeychain/src/main/res/layout/create_key_start_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_key_start_fragment.xml
@@ -74,6 +74,7 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
android:layout_weight="1"
android:text="@string/first_time_import_key"
android:textAllCaps="true"
@@ -91,6 +92,7 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
android:layout_weight="1"
android:text="@string/btn_do_not_save"
android:textAllCaps="true"
diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_blank_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_blank_fragment.xml
index ca203d0b5..7e2bf2246 100644
--- a/OpenKeychain/src/main/res/layout/create_yubi_key_blank_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_yubi_key_blank_fragment.xml
@@ -45,6 +45,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_gravity="center_vertical"
android:text="@string/btn_back"
android:textAllCaps="true"
android:minHeight="?android:attr/listPreferredItemHeight"
@@ -52,8 +53,7 @@
android:drawablePadding="8dp"
android:gravity="left|center_vertical"
android:clickable="true"
- style="?android:attr/borderlessButtonStyle"
- android:layout_gravity="center_vertical" />
+ style="?android:attr/borderlessButtonStyle" />
<TextView
android:id="@+id/create_key_next_button"
@@ -63,6 +63,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_gravity="center_vertical"
android:text="@string/first_time_blank_yubikey_yes"
android:textAllCaps="true"
android:minHeight="?android:attr/listPreferredItemHeight"
@@ -70,7 +71,6 @@
android:drawablePadding="8dp"
android:gravity="center_vertical|right"
android:clickable="true"
- style="?android:attr/borderlessButtonStyle"
- android:layout_gravity="center_vertical" />
+ style="?android:attr/borderlessButtonStyle" />
</LinearLayout>
</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_import_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_import_fragment.xml
deleted file mode 100644
index 838ee37b4..000000000
--- a/OpenKeychain/src/main/res/layout/create_yubi_key_import_fragment.xml
+++ /dev/null
@@ -1,126 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="4dp"
- android:orientation="horizontal"
- android:id="@+id/yubikey_status_layout" >
-
- <ImageView
- android:layout_margin="14dp"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:scaleType="centerCrop"
- android:src="@drawable/yubi_icon"/>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_weight="1"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/yubikey_serno"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="Yubikey #"
- />
-
- <TextView
- android:id="@+id/yubikey_userid"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="User ID"
- />
-
- <TextView
- android:id="@+id/yubikey_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="Unknown key, hit next to import"
- />
-
- </LinearLayout>
-
- <ImageButton
- android:id="@+id/button_search"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:padding="8dp"
- android:src="@drawable/ic_search_grey_24dp"
- android:layout_gravity="center_vertical"
- android:background="?android:selectableItemBackground" />
-
- </LinearLayout>
-
- <View
- android:layout_width="match_parent"
- android:layout_marginTop="4dp"
- android:layout_height="1dip"
- android:layout_below="@id/yubikey_status_layout"
- android:background="?android:attr/listDivider" />
-
- <FrameLayout
- android:id="@+id/yubikey_import_fragment"
- android:layout_marginTop="8dp"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/yubikey_status_layout"
- android:layout_above="@id/create_key_buttons"
- />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_alignParentBottom="true"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:background="?attr/colorButtonRow"
- android:id="@+id/create_key_buttons">
-
- <TextView
- android:id="@+id/create_key_back_button"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/btn_back"
- android:textAllCaps="true"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:drawableLeft="@drawable/ic_chevron_left_grey_24dp"
- android:drawablePadding="8dp"
- android:gravity="left|center_vertical"
- android:clickable="true"
- style="?android:attr/borderlessButtonStyle" />
-
- <TextView
- android:id="@+id/create_key_next_button"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/btn_import"
- android:textAllCaps="true"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:drawableRight="@drawable/ic_key_plus_grey600_24dp"
- android:drawablePadding="8dp"
- android:gravity="right|center_vertical"
- android:clickable="true"
- style="?android:attr/borderlessButtonStyle" />
-
- </LinearLayout>
-
-</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_import_reset_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_import_reset_fragment.xml
new file mode 100644
index 000000000..7acc2dca9
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/create_yubi_key_import_reset_fragment.xml
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_above="@+id/create_key_buttons"
+ android:fillViewport="true">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:id="@+id/yubikey_status_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="4dp">
+
+ <ImageView
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_margin="14dp"
+ android:scaleType="centerCrop"
+ android:src="@drawable/yubi_icon" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/yubikey_serno"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:text="Yubikey #" />
+
+ <TextView
+ android:id="@+id/yubikey_userid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:text="User ID" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/yubikey_decision"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/yubikey_status_layout"
+ android:orientation="vertical"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginTop="8dp"
+ android:text="@string/yubikey_reset_or_import"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <RadioGroup
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <RadioButton
+ android:id="@+id/yubikey_decision_import"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="@string/yubikey_import_radio" />
+
+ <RadioButton
+ android:id="@+id/yubikey_decision_reset"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginTop="16dp"
+ android:text="@string/yubikey_reset_radio" />
+ </RadioGroup>
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_below="@id/yubikey_decision"
+ android:layout_marginTop="4dp"
+ android:background="?android:attr/listDivider" />
+
+ <FrameLayout
+ android:id="@+id/yubikey_import_fragment"
+ android:layout_width="fill_parent"
+ android:layout_height="match_parent"
+ android:layout_below="@id/yubikey_decision"
+ android:layout_marginTop="8dp">
+
+ <TextView
+ android:id="@+id/yubikey_import_reset_warning"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_margin="24dp"
+ android:text="@string/yubikey_reset_warning"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/android_red_dark"
+ android:visibility="gone" />
+ </FrameLayout>
+
+ </RelativeLayout>
+ </ScrollView>
+
+ <LinearLayout
+ android:id="@+id/create_key_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:background="?attr/colorButtonRow"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/create_key_back_button"
+ style="?android:attr/borderlessButtonStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:clickable="true"
+ android:drawableLeft="@drawable/ic_chevron_left_grey_24dp"
+ android:drawablePadding="8dp"
+ android:gravity="left|center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:text="@string/btn_back"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:id="@+id/create_key_next_button"
+ style="?android:attr/borderlessButtonStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:clickable="true"
+ android:drawablePadding="8dp"
+ android:drawableRight="@drawable/ic_key_plus_grey600_24dp"
+ android:gravity="right|center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:text="@string/btn_import"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:visibility="invisible" />
+
+ </LinearLayout>
+
+</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_pin_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_pin_fragment.xml
index 393ec76d4..c3b73d91f 100644
--- a/OpenKeychain/src/main/res/layout/create_yubi_key_pin_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_yubi_key_pin_fragment.xml
@@ -7,55 +7,74 @@
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:fillViewport="true"
- android:layout_above="@+id/create_key_buttons">
+ android:layout_above="@+id/create_key_buttons"
+ android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:orientation="vertical"
android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:orientation="vertical">
+ android:paddingRight="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
android:layout_marginLeft="8dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@string/create_key_yubi_key_pin_text" />
+ android:layout_marginTop="16dp"
+ android:text="@string/create_key_yubi_key_pin_text"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
android:layout_marginLeft="8dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@string/create_key_yubi_key_pin" />
+ android:layout_marginTop="16dp"
+ android:text="@string/create_key_yubi_key_pin"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
- <TextView
+ <EditText
android:id="@+id/create_yubi_key_pin"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginBottom="8dp"
+ android:ems="10"
+ android:hint="@string/create_key_yubi_key_pin"
+ android:inputType="numberPassword" />
+
+ <EditText
+ android:id="@+id/create_yubi_key_pin_repeat"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="8dp"
+ android:ems="10"
+ android:hint="@string/create_key_yubi_key_pin_repeat"
+ android:inputType="numberPassword" />
+
+ <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
- android:textAppearance="?android:attr/textAppearanceLarge"
- tools:text="123456" />
+ android:layout_marginTop="48dp"
+ android:text="@string/create_key_yubi_key_admin_pin_text"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
android:layout_marginLeft="8dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@string/create_key_yubi_key_admin_pin" />
+ android:layout_marginTop="16dp"
+ android:text="@string/create_key_yubi_key_admin_pin"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/create_yubi_key_admin_pin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="48dp"
android:textAppearance="?android:attr/textAppearanceLarge"
tools:text="12345678" />
@@ -63,47 +82,49 @@
</ScrollView>
<LinearLayout
+ android:id="@+id/create_key_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:background="?attr/colorButtonRow"
- android:id="@+id/create_key_buttons">
+ android:orientation="horizontal">
<TextView
android:id="@+id/create_key_back_button"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
+ style="?android:attr/borderlessButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
android:layout_weight="1"
- android:text="@string/btn_back"
- android:textAllCaps="true"
- android:minHeight="?android:attr/listPreferredItemHeight"
+ android:clickable="true"
android:drawableLeft="@drawable/ic_chevron_left_grey_24dp"
android:drawablePadding="8dp"
android:gravity="left|center_vertical"
- android:clickable="true"
- style="?android:attr/borderlessButtonStyle" />
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:text="@string/btn_back"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/create_key_next_button"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
+ style="?android:attr/borderlessButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
android:layout_weight="1"
- android:text="@string/btn_next"
- android:textAllCaps="true"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:drawableRight="@drawable/ic_chevron_right_grey_24dp"
+ android:clickable="true"
android:drawablePadding="8dp"
+ android:drawableRight="@drawable/ic_chevron_right_grey_24dp"
android:gravity="right|center_vertical"
- android:clickable="true"
- style="?android:attr/borderlessButtonStyle" />
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:text="@string/btn_next"
+ android:textAllCaps="true"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_pin_repeat_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_pin_repeat_fragment.xml
deleted file mode 100644
index d233398ca..000000000
--- a/OpenKeychain/src/main/res/layout/create_yubi_key_pin_repeat_fragment.xml
+++ /dev/null
@@ -1,110 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <ScrollView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_above="@+id/create_key_buttons"
- android:fillViewport="true">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingLeft="16dp"
- android:paddingRight="16dp">
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/create_key_yubi_key_pin_repeat_text"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/create_key_yubi_key_pin"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <EditText
- android:id="@+id/create_yubi_key_pin_repeat"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="8dp"
- android:ems="10"
- android:hint="@string/create_key_yubi_key_pin_repeat"
- android:inputType="numberPassword" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/create_key_yubi_key_admin_pin"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <EditText
- android:id="@+id/create_yubi_key_admin_pin_repeat"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_marginBottom="8dp"
- android:ems="10"
- android:hint="@string/create_key_yubi_key_admin_pin_repeat"
- android:inputType="numberPassword" />
-
- </LinearLayout>
- </ScrollView>
-
- <LinearLayout
- android:id="@+id/create_key_buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:background="?attr/colorButtonRow"
- android:orientation="horizontal">
-
- <TextView
- android:id="@+id/create_key_back_button"
- style="?android:attr/borderlessButtonStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:clickable="true"
- android:drawableLeft="@drawable/ic_chevron_left_grey_24dp"
- android:drawablePadding="8dp"
- android:gravity="left|center_vertical"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:text="@string/btn_back"
- android:textAllCaps="true"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <TextView
- android:id="@+id/create_key_next_button"
- style="?android:attr/borderlessButtonStyle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:clickable="true"
- android:drawablePadding="8dp"
- android:drawableRight="@drawable/ic_chevron_right_grey_24dp"
- android:gravity="right|center_vertical"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:text="@string/btn_next"
- android:textAllCaps="true"
- android:textAppearance="?android:attr/textAppearanceMedium" />
- </LinearLayout>
-</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/create_yubi_key_wait_fragment.xml b/OpenKeychain/src/main/res/layout/create_yubi_key_wait_fragment.xml
index a000dc82e..7f26995a7 100644
--- a/OpenKeychain/src/main/res/layout/create_yubi_key_wait_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_yubi_key_wait_fragment.xml
@@ -56,27 +56,11 @@
android:minHeight="?android:attr/listPreferredItemHeight"
android:drawableLeft="@drawable/ic_chevron_left_grey_24dp"
android:drawablePadding="8dp"
+ android:layout_gravity="center_vertical"
android:gravity="left|center_vertical"
android:clickable="true"
style="?android:attr/borderlessButtonStyle" />
- <TextView
- android:id="@+id/create_key_next_button"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/btn_next"
- android:textAllCaps="true"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:drawableRight="@drawable/yubi_icon_24dp"
- android:drawablePadding="16dp"
- android:gravity="right|center_vertical"
- android:clickable="false"
- style="?android:attr/borderlessButtonStyle" />
-
</LinearLayout>
</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/decrypt_list_entry.xml b/OpenKeychain/src/main/res/layout/decrypt_list_entry.xml
index 7869b9a8a..8bdfce733 100644
--- a/OpenKeychain/src/main/res/layout/decrypt_list_entry.xml
+++ b/OpenKeychain/src/main/res/layout/decrypt_list_entry.xml
@@ -26,7 +26,6 @@
android:measureAllChildren="false"
custom:initialView="1"
android:minHeight="?listPreferredItemHeightSmall"
- android:animateLayoutChanges="true"
>
<LinearLayout
@@ -65,34 +64,35 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingRight="4dp"
- android:paddingLeft="4dp"
+ android:layout_marginTop="4dp"
+ android:layout_marginBottom="4dp"
+ android:gravity="center_vertical"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/result_encryption_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:padding="4dp"
android:src="@drawable/status_lock_open_24dp"
- android:layout_gravity="center_vertical" />
+ />
<TextView
android:id="@+id/result_encryption_text"
android:layout_width="0dp"
- android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_marginLeft="8dp"
- android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp"
+ android:layout_marginLeft="6dp"
android:text=""
tools:text="Encryption status text" />
<ImageView
android:id="@+id/context_menu"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="4dp"
android:scaleType="center"
- android:layout_width="36dip"
- android:layout_height="48dip"
android:clickable="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_more_vert_black_24dp" />
@@ -103,25 +103,26 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingRight="4dp"
- android:paddingLeft="4dp"
+ android:layout_marginTop="4dp"
+ android:layout_marginBottom="4dp"
+ android:gravity="center_vertical"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/result_signature_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:padding="4dp"
android:src="@drawable/status_signature_unverified_cutout_24dp"
- android:layout_gravity="center_vertical" />
+ />
<TextView
android:id="@+id/result_signature_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_marginLeft="8dp"
- android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp"
+ android:layout_marginLeft="6dp"
android:text=""
tools:text="Signature status text" />
</LinearLayout>
@@ -130,10 +131,12 @@
android:id="@+id/result_signature_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginTop="2dp"
+ android:layout_marginBottom="2dp"
android:clickable="true"
android:background="?android:selectableItemBackground"
android:orientation="horizontal"
- style="?listPreferredItemHeight"
+ android:minHeight="40dp"
>
<LinearLayout
@@ -142,7 +145,7 @@
android:layout_weight="1"
android:paddingRight="4dp"
android:paddingLeft="4dp"
- android:gravity="center_vertical"
+ android:layout_gravity="center_vertical"
android:orientation="vertical">
<TextView
@@ -160,6 +163,8 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:text=""
+ android:singleLine="true"
+ android:ellipsize="end"
tools:text="alice@example.com" />
</LinearLayout>
@@ -172,19 +177,45 @@
android:layout_marginTop="8dp"
android:background="?android:attr/listDivider" />
- <TextView
- android:id="@+id/result_signature_action"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:textAppearance="?android:attr/textAppearanceMedium"
+ <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:drawableRight="@drawable/ic_vpn_key_grey_24dp"
- android:drawablePadding="8dp"
- android:gravity="center_vertical"
- android:text=""
- tools:text="Show"
- />
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:id="@+id/result_signature_action"
+ android:measureAllChildren="true"
+ android:inAnimation="@anim/fade_in"
+ android:outAnimation="@anim/fade_out"
+ custom:initialView="0"
+ >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:drawableRight="@drawable/ic_vpn_key_grey_24dp"
+ android:drawablePadding="8dp"
+ android:text="@string/decrypt_result_action_show"
+ />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:drawableRight="@drawable/ic_file_download_grey_24dp"
+ android:drawablePadding="8dp"
+ android:text="@string/decrypt_result_action_Lookup"
+ />
+
+ <ProgressBar
+ android:layout_width="30dp"
+ android:layout_height="30dp"
+ android:padding="4dp"
+ android:layout_gravity="center" />
+
+ </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/encrypt_decrypt_overview_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_decrypt_fragment.xml
index 7bd919abc..7bd919abc 100644
--- a/OpenKeychain/src/main/res/layout/encrypt_decrypt_overview_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/encrypt_decrypt_fragment.xml
diff --git a/OpenKeychain/src/main/res/layout/import_keys_activity.xml b/OpenKeychain/src/main/res/layout/import_keys_activity.xml
index 28bb8a0b8..6602c4b8f 100644
--- a/OpenKeychain/src/main/res/layout/import_keys_activity.xml
+++ b/OpenKeychain/src/main/res/layout/import_keys_activity.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ xmlns:tools="http://schemas.android.com/tools">
<include
android:id="@+id/toolbar_include"
@@ -21,16 +22,26 @@
<include layout="@layout/notify_area" />
- <FrameLayout
- android:id="@+id/import_keys_top_container"
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="64dp"
- android:orientation="vertical" />
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:id="@+id/import_keys_top_layout"
+ android:visibility="gone"
+ tools:visibility="visible">
- <View
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:background="?android:attr/listDivider" />
+ <FrameLayout
+ android:id="@+id/import_keys_top_container"
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:orientation="vertical" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+
+ </LinearLayout>
<FrameLayout
android:id="@+id/import_keys_list_container"
diff --git a/OpenKeychain/src/main/res/layout/key_list_fragment.xml b/OpenKeychain/src/main/res/layout/key_list_fragment.xml
index 26cedd362..6aaf5be25 100644
--- a/OpenKeychain/src/main/res/layout/key_list_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/key_list_fragment.xml
@@ -3,6 +3,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
+ xmlns:tools="http://schemas.android.com/tools"
+ xmlns:custom="http://schemas.android.com/apk/res-auto"
>
<!--rebuild functionality of ListFragment -->
@@ -23,10 +25,11 @@
<LinearLayout
android:id="@+id/key_list_empty"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="240dp"
android:gravity="center"
android:orientation="vertical"
- android:visibility="visible">
+ android:animateLayoutChanges="true"
+ >
<TextView
android:layout_width="wrap_content"
@@ -35,6 +38,30 @@
android:text="@string/key_list_empty_text1"
android:textAppearance="?android:attr/textAppearanceLarge" />
+ <org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/search_container"
+ android:inAnimation="@anim/fade_in_delayed"
+ android:outAnimation="@anim/fade_out"
+ android:measureAllChildren="true"
+ custom:initialView="1">
+
+ <Space
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="24dp"
+ android:id="@+id/search_button"
+ android:gravity="center"
+ tools:text="@string/btn_search_for_query"
+ />
+
+ </org.sufficientlysecure.keychain.ui.widget.ToolableViewAnimator>
+
</LinearLayout>
</FrameLayout>
diff --git a/OpenKeychain/src/main/res/layout/linked_create_github_fragment.xml b/OpenKeychain/src/main/res/layout/linked_create_github_fragment.xml
index e1c8db383..7fa581905 100644
--- a/OpenKeychain/src/main/res/layout/linked_create_github_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/linked_create_github_fragment.xml
@@ -156,7 +156,7 @@
android:drawableLeft="@drawable/ic_repeat_black_24dp"
android:drawableStart="@drawable/ic_repeat_black_24dp"
android:drawablePadding="12dp"
- android:text="@string/linked_button_retry"
+ android:text="@string/linked_button_retry_step"
android:id="@+id/button_retry"
/>
diff --git a/OpenKeychain/src/main/res/layout/linked_id_item.xml b/OpenKeychain/src/main/res/layout/linked_id_item.xml
index e4fe58551..d6e437dd5 100644
--- a/OpenKeychain/src/main/res/layout/linked_id_item.xml
+++ b/OpenKeychain/src/main/res/layout/linked_id_item.xml
@@ -6,7 +6,6 @@
android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal"
android:singleLine="true"
- android:background="#ffffff"
tools:showIn="@layout/linked_id_view_fragment">
<ImageView
diff --git a/OpenKeychain/src/main/res/layout/linked_id_view_fragment.xml b/OpenKeychain/src/main/res/layout/linked_id_view_fragment.xml
index 377ce4fb6..8b275fcef 100644
--- a/OpenKeychain/src/main/res/layout/linked_id_view_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/linked_id_view_fragment.xml
@@ -14,7 +14,7 @@
android:transitionName="card_linked_ids"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- card_view:cardBackgroundColor="@android:color/white"
+ card_view:cardBackgroundColor="?attr/colorCardViewBackground"
card_view:cardElevation="2dp"
card_view:cardUseCompatPadding="true"
card_view:cardCornerRadius="4dp">
diff --git a/OpenKeychain/src/main/res/layout/nfc_operation_activity.xml b/OpenKeychain/src/main/res/layout/nfc_operation_activity.xml
index 9a9738825..d3ee363d5 100644
--- a/OpenKeychain/src/main/res/layout/nfc_operation_activity.xml
+++ b/OpenKeychain/src/main/res/layout/nfc_operation_activity.xml
@@ -41,6 +41,16 @@
android:adjustViewBounds="true"
android:background="@android:color/transparent"
android:src="@drawable/yubikey_phone" />
+
+ <Button
+ android:id="@+id/nfc_activity_0_cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_below="@+id/nfc_activity_0_image"
+ android:layout_margin="8dp"
+ android:text="@string/progress_cancel" />
</RelativeLayout>
<RelativeLayout
@@ -79,6 +89,17 @@
android:src="@drawable/yubikey_phone"
android:visibility="invisible" />
+ <Button
+ android:id="@+id/nfc_activity_1_button_placeholder"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_below="@+id/nfc_activity_1_placeholder"
+ android:layout_margin="8dp"
+ android:text=""
+ android:visibility="invisible" />
+
</RelativeLayout>
<RelativeLayout
@@ -118,6 +139,17 @@
android:background="@android:color/transparent"
android:src="@drawable/ic_check_circle_black_48dp" />
+ <Button
+ android:id="@+id/nfc_activity_2_button_placeholder"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_below="@+id/nfc_activity_2_placeholder"
+ android:layout_margin="8dp"
+ android:text=""
+ android:visibility="invisible" />
+
</RelativeLayout>
<RelativeLayout
diff --git a/OpenKeychain/src/main/res/layout/passphrase_dialog_backup_code.xml b/OpenKeychain/src/main/res/layout/passphrase_dialog_backup_code.xml
new file mode 100644
index 000000000..0ffa695cf
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/passphrase_dialog_backup_code.xml
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="14dp"
+ android:paddingTop="14dp">
+
+ <LinearLayout
+ android:id="@+id/input"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/passphrase_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="24dp"
+ android:text="@string/passphrase_for_backup"
+ android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="8dp">
+
+ <!--
+ The most reliable way to correctly size these I found was to put a transparent hint on them.
+ Theoretically, this should be what the android:ems attribute is for - didn't work for me.
+ -->
+ <EditText
+ android:id="@+id/backup_code_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="14dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="14dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <EditText
+ android:id="@+id/backup_code_2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="14dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="14dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <EditText
+ android:id="@+id/backup_code_3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="14dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:text="-"
+ android:textSize="14dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ <EditText
+ android:id="@+id/backup_code_4"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:hint="ABCDEF"
+ android:inputType="textNoSuggestions|textCapCharacters"
+ android:maxLength="6"
+ android:singleLine="true"
+ android:textColorHint="@android:color/transparent"
+ android:textSize="14dp"
+ android:textStyle="bold"
+ android:typeface="monospace"
+ tools:ignore="HardcodedText,SpUsage" />
+
+ </LinearLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/progress"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:orientation="horizontal"
+ android:visibility="invisible">
+
+ <ProgressBar
+ style="?android:attr/progressBarStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal" />
+
+ <TextView
+ style="?android:attr/textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:padding="4dp"
+ android:text="@string/label_unlock" />
+
+ </LinearLayout>
+
+</RelativeLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/qr_code_capture_activity.xml b/OpenKeychain/src/main/res/layout/qr_code_capture_activity.xml
new file mode 100644
index 000000000..094901740
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/qr_code_capture_activity.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <com.journeyapps.barcodescanner.CompoundBarcodeView
+ android:id="@+id/zxing_barcode_scanner"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentBottom="true" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/toolbar_tabs.xml b/OpenKeychain/src/main/res/layout/toolbar_tabs.xml
index ed42ef52e..315aaf75a 100644
--- a/OpenKeychain/src/main/res/layout/toolbar_tabs.xml
+++ b/OpenKeychain/src/main/res/layout/toolbar_tabs.xml
@@ -18,7 +18,7 @@
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:textColor="?attr/colorTabText"
- app:pstsTextColorSelected="?attr/colorTabTextSelected"
+ app:pstsTabTextColor="?attr/colorTabTextSelected"
app:pstsIndicatorColor="?attr/colorTabIndicator" />
</RelativeLayout>
diff --git a/OpenKeychain/src/main/res/layout/view_key_adv_keybase_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_adv_keybase_fragment.xml
index 75d56e092..5fb9e79a2 100644
--- a/OpenKeychain/src/main/res/layout/view_key_adv_keybase_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_adv_keybase_fragment.xml
@@ -30,20 +30,6 @@
android:layout_height="wrap_content"
android:text="@string/section_keybase_proofs" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="?attr/colorButtonRow"
- android:gravity="center_horizontal"
- android:padding="8dp"
- android:text="@string/key_trust_header_text"
- android:textAppearance="?android:attr/textAppearanceSmall" />
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:background="?android:attr/listDivider" />
-
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml
index d82506e74..c08d66cc1 100644
--- a/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml
@@ -126,23 +126,6 @@
android:background="?android:attr/listDivider" />
<ImageButton
- android:id="@+id/view_key_action_key_export"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:padding="8dp"
- android:src="@drawable/ic_save_grey_24dp"
- android:layout_gravity="center_vertical"
- android:background="?android:selectableItemBackground" />
-
- <View
- android:layout_width="1dip"
- android:layout_height="match_parent"
- android:gravity="right"
- android:layout_marginBottom="8dp"
- android:layout_marginTop="8dp"
- android:background="?android:attr/listDivider" />
-
- <ImageButton
android:id="@+id/view_key_action_key_nfc"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/OpenKeychain/src/main/res/layout/view_key_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_fragment.xml
index 5bf36f564..8715945bf 100644
--- a/OpenKeychain/src/main/res/layout/view_key_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_fragment.xml
@@ -17,7 +17,7 @@
android:layout_height="wrap_content"
android:visibility="gone"
tools:visibility="visible"
- card_view:cardBackgroundColor="@android:color/white"
+ card_view:cardBackgroundColor="?attr/colorCardViewBackground"
card_view:cardElevation="2dp"
card_view:cardUseCompatPadding="true"
card_view:cardCornerRadius="4dp">
diff --git a/OpenKeychain/src/main/res/menu-v19/decrypt_bottom_sheet.xml b/OpenKeychain/src/main/res/menu-v19/decrypt_bottom_sheet.xml
new file mode 100644
index 000000000..868bd605f
--- /dev/null
+++ b/OpenKeychain/src/main/res/menu-v19/decrypt_bottom_sheet.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:id="@+id/decrypt_open"
+ android:icon="@drawable/ic_apps_black_24dp"
+ android:title="@string/btn_open_with" />
+
+ <item
+ android:id="@+id/decrypt_share"
+ android:icon="@drawable/ic_share_black_24dp"
+ android:title="@string/btn_share_decrypted_text" />
+
+ <item
+ android:id="@+id/decrypt_save"
+ android:icon="@drawable/ic_save_black_24dp"
+ android:title="@string/btn_save" />
+
+</menu>
diff --git a/OpenKeychain/src/main/res/menu/decrypt_bottom_sheet.xml b/OpenKeychain/src/main/res/menu/decrypt_bottom_sheet.xml
index 11b79bd5f..f3550278a 100644
--- a/OpenKeychain/src/main/res/menu/decrypt_bottom_sheet.xml
+++ b/OpenKeychain/src/main/res/menu/decrypt_bottom_sheet.xml
@@ -3,17 +3,12 @@
<item
android:id="@+id/decrypt_open"
- android:title="Open with…"
- android:icon="@drawable/ic_apps_black_24dp" />
+ android:icon="@drawable/ic_apps_black_24dp"
+ android:title="@string/btn_open_with" />
<item
android:id="@+id/decrypt_share"
- android:title="@string/btn_share_decrypted_text"
- android:icon="@drawable/ic_share_black_24dp" />
+ android:icon="@drawable/ic_share_black_24dp"
+ android:title="@string/btn_share_decrypted_text" />
- <item
- android:id="@+id/decrypt_save"
- android:title="@string/btn_save"
- android:icon="@drawable/ic_save_black_24dp" />
-
-</menu>
+</menu> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/menu/encrypt_text_fragment.xml b/OpenKeychain/src/main/res/menu/encrypt_text_fragment.xml
index 80b78457d..4d3d53870 100644
--- a/OpenKeychain/src/main/res/menu/encrypt_text_fragment.xml
+++ b/OpenKeychain/src/main/res/menu/encrypt_text_fragment.xml
@@ -3,6 +3,14 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
+ android:id="@+id/encrypt_paste"
+ android:title="@string/btn_paste_encrypted_signed"
+ android:icon="@drawable/ic_action_encrypt_paste_24dp"
+ android:orderInCategory="1"
+ android:visible="false"
+ app:showAsAction="ifRoom" />
+
+ <item
android:id="@+id/encrypt_copy"
android:title="@string/btn_copy_encrypted_signed"
android:icon="@drawable/ic_action_encrypt_copy_24dp"
diff --git a/OpenKeychain/src/main/res/menu/key_list.xml b/OpenKeychain/src/main/res/menu/key_list.xml
index d3a2bd0fd..edaf0c999 100644
--- a/OpenKeychain/src/main/res/menu/key_list.xml
+++ b/OpenKeychain/src/main/res/menu/key_list.xml
@@ -26,6 +26,12 @@
app:showAsAction="never" />
<item
+ android:id="@+id/menu_key_list_debug_bench"
+ android:title="Debug / Benchmark"
+ android:visible="false"
+ app:showAsAction="never" />
+
+ <item
android:id="@+id/menu_key_list_debug_read"
android:title="Debug / DB restore"
android:visible="false"
diff --git a/OpenKeychain/src/main/res/menu/key_view.xml b/OpenKeychain/src/main/res/menu/key_view.xml
index 14ea099f4..c0adfcd6f 100644
--- a/OpenKeychain/src/main/res/menu/key_view.xml
+++ b/OpenKeychain/src/main/res/menu/key_view.xml
@@ -16,7 +16,7 @@
android:title="@string/key_view_action_update" />
<item
- android:id="@+id/menu_key_view_export_file"
+ android:id="@+id/menu_key_view_backup"
app:showAsAction="never"
android:title="@string/menu_export_key" />
@@ -41,7 +41,7 @@
android:id="@+id/menu_key_view_certify_fingerprint_word"
app:showAsAction="never"
android:visible="false"
- android:title="@string/menu_certify_fingerprint_word" />
+ android:title="@string/menu_certify_fingerprint_phrases" />
<item
android:id="@+id/menu_key_view_add_linked_identity"
diff --git a/OpenKeychain/src/main/res/raw-cs/help_about.md b/OpenKeychain/src/main/res/raw-cs/help_about.md
index 06bed0021..3538e68cc 100644
--- a/OpenKeychain/src/main/res/raw-cs/help_about.md
+++ b/OpenKeychain/src/main/res/raw-cs/help_about.md
@@ -1,8 +1,8 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) is an OpenPGP implementation for Android.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
License: GPLv3+
@@ -61,11 +61,11 @@ License: GPLv3+
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache License v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache License v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT License)
* [Snackbar](https://github.com/nispok/snackbar) (MIT License)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 License)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache License v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache License v2)
* [ZXing](https://github.com/zxing/zxing) (Apache License v2)
diff --git a/OpenKeychain/src/main/res/raw-cs/help_changelog.md b/OpenKeychain/src/main/res/raw-cs/help_changelog.md
index 11d7975b1..60deb1c48 100644
--- a/OpenKeychain/src/main/res/raw-cs/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-cs/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Key revocation on key deletion
diff --git a/OpenKeychain/src/main/res/raw-de/help_about.md b/OpenKeychain/src/main/res/raw-de/help_about.md
index c19b9d8a6..64af3c07f 100644
--- a/OpenKeychain/src/main/res/raw-de/help_about.md
+++ b/OpenKeychain/src/main/res/raw-de/help_about.md
@@ -1,12 +1,12 @@
-[//]: # (Beachte: Bitte schreibe jeden Satz in eine eigene Zeile, Transifex wird jede Zeile in ein eigenes Übesetzungsfeld setzen!)
+[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) ist eine OpenPGP-Implementierung für Android.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
Lizenz: GPLv3+
-[//]: # (Beachte: alphabethisch Sortiert)
+[//]: # (Beachte: alphabethische Sortierung)
## Hauptentwickler
* Dominik Schürmann (Leitender Entwickler)
@@ -51,7 +51,7 @@ Lizenz: GPLv3+
* Sreeram Boyapati
* 'steelman'
-[//]: # (Beachte: alphabethisch Sortiert)
+[//]: # (Beachte: alphabethische Sortierung)
## Bibliotheken
* [Android Support Libraries](http://developer.android.com/tools/support-library/index.html) (Apache-Lizenz v2)
@@ -61,11 +61,11 @@ Lizenz: GPLv3+
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache-Lizenz v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache-Lizenz v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache-Lizenz v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache-Lizenz v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache-Lizenz v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT-Lizenz)
* [Snackbar](https://github.com/nispok/snackbar) (MIT-Lizenz)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11-Lizenz)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache-Lizenz v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache-Lizenz v2)
* [ZXing](https://github.com/zxing/zxing) (Apache-Lizenz v2)
diff --git a/OpenKeychain/src/main/res/raw-de/help_changelog.md b/OpenKeychain/src/main/res/raw-de/help_changelog.md
index 91f2ffedc..cb21b53ed 100644
--- a/OpenKeychain/src/main/res/raw-de/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-de/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTITZ: Bitte setze jeden Satz in eine eigene Zeile, Transifex setzt jede Zeile in ein eigenes Übersetzungsfeld!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Schlüsselwiderruf bei Schlüssellöschung
diff --git a/OpenKeychain/src/main/res/raw-es/help_about.md b/OpenKeychain/src/main/res/raw-es/help_about.md
index 194adfd3a..27dc7a59a 100644
--- a/OpenKeychain/src/main/res/raw-es/help_about.md
+++ b/OpenKeychain/src/main/res/raw-es/help_about.md
@@ -1,8 +1,8 @@
[//]: # (NOTA: ¡Ponga cada frase en su propia línea, Transifex pone cada línea en su propio campo de traducción!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) es una implementación de OpenPGP para Android.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
Licencia: GPLv3+
@@ -61,11 +61,11 @@ Licencia: GPLv3+
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Licencia Apache v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Licencia Apache v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Licencia Apache v2)
- * [OkHttp](http://square.github.io/okhttp/) (Licencia Apache v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Licencia Apache v2)
* [Librería SafeSlinger Exchange](https://github.com/SafeSlingerProject/exchange-android) (Licencia MIT)
* [Snackbar](https://github.com/nispok/snackbar) (Licencia MIT)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (Licencia MIT X11)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Licencia Apache v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Licencia Apache v2)
* [ZXing](https://github.com/zxing/zxing) (Licencia Apache v2)
diff --git a/OpenKeychain/src/main/res/raw-es/help_changelog.md b/OpenKeychain/src/main/res/raw-es/help_changelog.md
index 49855890d..e91d68bc2 100644
--- a/OpenKeychain/src/main/res/raw-es/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-es/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTA: ¡Por favor ponga cada frase en su propia línea, Transifex pone cada línea en su propio campo de traducción!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Revocación de clave al borrar clave
diff --git a/OpenKeychain/src/main/res/raw-eu/help_about.md b/OpenKeychain/src/main/res/raw-eu/help_about.md
index 09a7737d4..f5c54b18c 100644
--- a/OpenKeychain/src/main/res/raw-eu/help_about.md
+++ b/OpenKeychain/src/main/res/raw-eu/help_about.md
@@ -1,25 +1,25 @@
[//]: # (OHARRA: Meseez jarri esaldi bakoitza bere lerroan, Transifex-ek lerroak bere itzulpen eremuan jartzen ditu!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) Android-rako OpenPGP egokitzapen bat da.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
Baimena: GPLv3+
-[//]: # (NOTE: Alphabetic ordering)
+[//]: # (OHARRA: Alfabetikoki antolatuta)
## Garatzaile Nagusiak
* Dominik Schürmann (Mantentzaileak)
* Vincent Breitmoser
-## Top Contributors
+## Laguntzaile Nagusiak
* Adithya Abraham Philip
* Ash Hughes
* 'mar-v-in'
* 'Thialfihar' (APG garatzailea)
* Tim Bray
-## Occasional Contributors
+## Tartekako Laguntzaileak
* Art O Cathain
* Brian C. Barnes
* Bahtiar 'kalkin' Gadimov
@@ -51,7 +51,7 @@ Baimena: GPLv3+
* Sreeram Boyapati
* 'steelman'
-[//]: # (NOTE: Alphabetic ordering)
+[//]: # (OHARRA: Alfabetikoki antolatuta)
## Liburutegiak
* [Android Support Libraries](http://developer.android.com/tools/support-library/index.html) (Apache Baimena v2)
@@ -61,11 +61,11 @@ Baimena: GPLv3+
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache Baimena v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache Baimena v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache Baimena v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Diseinua) (Apache Baimena 2 bertsioa)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT Baimena)
* [Snackbar](https://github.com/nispok/snackbar) (MIT Baimena)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 Baimena)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache Baimena v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache Baimena v2)
* [ZXing](https://github.com/zxing/zxing) (Apache Baimena v2)
diff --git a/OpenKeychain/src/main/res/raw-eu/help_changelog.md b/OpenKeychain/src/main/res/raw-eu/help_changelog.md
index d9a918b92..337393c31 100644
--- a/OpenKeychain/src/main/res/raw-eu/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-eu/help_changelog.md
@@ -1,11 +1,23 @@
[//]: # (OHARRA: Meseez jarri esaldi bakoitza bere lerroan, Transifex-ek lerroak bere itzulpen eremuan jartzen ditu!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
- * Key revocation on key deletion
- * Improved checks for insecure cryptography
- * Fix: Don't close OpenKeychain after first time wizard succeeds
- * API: Version 8
+ * Giltza ukapena giltza ezabatzean
+ * Hobetuta segurtasun gabeko kriptografia egiaztapena
+ * Zuzenduta: OpenKeychain ez da isten laguntzailearen lehen jardunaren ondoren
+ * API: 8 bertsioa
## 3.4
diff --git a/OpenKeychain/src/main/res/raw-fa/help_about.md b/OpenKeychain/src/main/res/raw-fa/help_about.md
index daecd5cbf..c1f4df2f2 100644
--- a/OpenKeychain/src/main/res/raw-fa/help_about.md
+++ b/OpenKeychain/src/main/res/raw-fa/help_about.md
@@ -1,8 +1,8 @@
[//]: # (تذکر: هر جمله در همان خط!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) یک نسخه از OpenPGP برای اندروید است.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
مجوز: GPLv3+
@@ -61,11 +61,11 @@
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache License v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache License v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT License)
* [Snackbar](https://github.com/nispok/snackbar) (MIT License)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 License)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache License v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache License v2)
* [ZXing](https://github.com/zxing/zxing) (Apache License v2)
diff --git a/OpenKeychain/src/main/res/raw-fa/help_changelog.md b/OpenKeychain/src/main/res/raw-fa/help_changelog.md
index e84775421..930156616 100644
--- a/OpenKeychain/src/main/res/raw-fa/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-fa/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (تذکر: هر جمله در همان خط!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Key revocation on key deletion
diff --git a/OpenKeychain/src/main/res/raw-fi/help_about.md b/OpenKeychain/src/main/res/raw-fi/help_about.md
index 06bed0021..3538e68cc 100644
--- a/OpenKeychain/src/main/res/raw-fi/help_about.md
+++ b/OpenKeychain/src/main/res/raw-fi/help_about.md
@@ -1,8 +1,8 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) is an OpenPGP implementation for Android.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
License: GPLv3+
@@ -61,11 +61,11 @@ License: GPLv3+
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache License v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache License v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT License)
* [Snackbar](https://github.com/nispok/snackbar) (MIT License)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 License)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache License v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache License v2)
* [ZXing](https://github.com/zxing/zxing) (Apache License v2)
diff --git a/OpenKeychain/src/main/res/raw-fi/help_changelog.md b/OpenKeychain/src/main/res/raw-fi/help_changelog.md
index 11d7975b1..60deb1c48 100644
--- a/OpenKeychain/src/main/res/raw-fi/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-fi/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Key revocation on key deletion
diff --git a/OpenKeychain/src/main/res/raw-fr/help_about.md b/OpenKeychain/src/main/res/raw-fr/help_about.md
index 5994ae4df..ec9a107ba 100644
--- a/OpenKeychain/src/main/res/raw-fr/help_about.md
+++ b/OpenKeychain/src/main/res/raw-fr/help_about.md
@@ -1,8 +1,8 @@
[//] : # (NOTE : veuillez mettre chaque phrase dans sa propre ligne. Transifex met chaque ligne dans son propre champ de traduction !)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) est une mise en œuvre d'OpenPGP pour Android.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
Licence : GPLv3+
@@ -61,11 +61,11 @@ Licence : GPLv3+
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Licence Apache v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Licence Apache v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Licence Apache v2)
- * [OkHttp](http://square.github.io/okhttp/) (licence Apache v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Conception matérielle)</a> (Licence Apache v2)
* [Bibliothèque d'échange SafeSlinger](https://github.com/SafeSlingerProject/exchange-android) (Licence MIT)
* [Snackbar](https://github.com/nispok/snackbar) (Licence MIT)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (Licence MIT X11)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Licence Apache v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Licence Apache v2)
* [ZXing](https://github.com/zxing/zxing) (Licence Apache v2)
diff --git a/OpenKeychain/src/main/res/raw-fr/help_changelog.md b/OpenKeychain/src/main/res/raw-fr/help_changelog.md
index 44e949c77..c31d53932 100644
--- a/OpenKeychain/src/main/res/raw-fr/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-fr/help_changelog.md
@@ -1,5 +1,17 @@
[//] : # (NOTE : veuillez mettre chaque phrase sur sa propre ligne. Transifex met chaque ligne dans son propre champ de traduction !)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* révocation de la clef lors de la suppression de la clef
@@ -11,17 +23,17 @@
* Téléchargement anonyme de clefs avec Tor
* Prise en charge des serveurs mandataires
- * Meilleur gestion des erreurs de la ClefYubi
+ * Meilleur gestion des erreurs Yubikey
## 3.3
* Nouvel écran de déchiffrement
* Déchiffrement simultané de plusieurs fichiers
- * Meilleure gestion des erreurs ClefYubi
+ * Meilleure gestion des erreurs Yubikey
## 3.2
- * Première version avec prise en charge complète de la ClefYubi, proposée dans l'interface utilisateur : modifier les clefs, relier la clef Yubi au clefs...
+ * Première version avec prise en charge complète de la Yubikey, proposée dans l'interface utilisateur : modifier les clefs, relier la Yubikey aux clefs...
* Conception matérielle
* Intégration de la lecture de code QR (nouvelles permissions exigées)
* Amélioration de l'assistant de création de clef
@@ -56,7 +68,7 @@
* Écran de déchiffrement redessiné
* Nouveaux agencement et couleurs d'icônes
* Importation des clefs secrètes corrigée de Symantec Encryption Desktop
- * Prise en charge expérimentale de la ClefYubi : les ID de sous-clefs sont maintenant vérifiés correctement
+ * Prise en charge expérimentale de la Yubikey : les ID de sous-clefs sont maintenant vérifiés correctement
## 3.0.1
@@ -75,13 +87,13 @@
* Corrigé - Certificats de révocation des ID utilisateurs
* Nouvelle recherche nuagique (dans les serveurs traditionnels et dans keybase.io)
* Prise en charge du dépouillement des clefs dans OpenKeychain
- * Prise en charge expérimentale de la ClefYubi : prise en charge de la génération de signature et le déchiffrement
+ * Prise en charge expérimentale de la Yubikey : prise en charge de la génération de signature et le déchiffrement
## 2.9.2
* Correctif - Clefs brisées dans 2.9.1
- * Prise en charge expérimentale de la ClefYubi : le déchiffrement fonctionne maintenant avec l'API
+ * Prise en charge expérimentale de la Yubikey : le déchiffrement fonctionne maintenant avec l'API
## 2.9.1
@@ -90,7 +102,7 @@
* Correctif - Gestion des drapeaux de clefs (prend maintenant en charge les clefs Mailvelope 0.7)
* Gestion des phrases de passe améliorée
* Partage de clefs par SafeSlinger
- * Prise en charge expérimentale de la ClefYubi : préférence pour permettre d'autres NIP, seule la signature par l'API OpenPGP fonctionne actuellement, mais pas dans OpenKeychain
+ * Prise en charge expérimentale de la Yubikey : préférence pour permettre d'autres NIP, seule la signature par l'API OpenPGP fonctionne actuellement, mais pas dans OpenKeychain
* Correctif - Utilisation de clefs dépouillées
* SHA256 par défaut pour la compatibilité
* L'API des intentions a changé, voir https://github.com/open-keychain/open-keychain/wiki/Intent-API
@@ -101,7 +113,7 @@
* Correction des plantages présents dans v2.8
* Prise en charge expérimentale CCE
- * Prise en charge expérimentale de la ClefYubi : signature seulement avec les clefs importées
+ * Prise en charge expérimentale de la Yubikey : signature seulement avec les clefs importées
## 2.8
diff --git a/OpenKeychain/src/main/res/raw-it/help_about.md b/OpenKeychain/src/main/res/raw-it/help_about.md
index dbf7b57a7..62a7a2687 100644
--- a/OpenKeychain/src/main/res/raw-it/help_about.md
+++ b/OpenKeychain/src/main/res/raw-it/help_about.md
@@ -1,25 +1,25 @@
[//]: # (NOTA: Si prega di mettere ogni frase in una propria linea, Transifex mette ogni riga nel proprio campo di traduzione!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) e un impelementazione OpenPGP per Android.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
Licenza: GPLv3+
-[//]: # (NOTE: Alphabetic ordering)
+[//]: # (NOTA: Ordine alfabetico)
## Sviluppatori principali
* Dominik Schürmann (Manutentore)
* Vincent Breitmoser
-## Top Contributors
+## Collaboratori principali
* Adithya Abraham Philip
* Ash Hughes
* 'mar-v-in'
* 'Thialfihar' (Sviluppatore APG)
* Tim Bray
-## Occasional Contributors
+## Collaboratori occasionali
* Art O Cathain
* Brian C. Barnes
* Bahtiar 'kalkin' Gadimov
@@ -51,7 +51,7 @@ Licenza: GPLv3+
* Sreeram Boyapati
* 'steelman'
-[//]: # (NOTE: Alphabetic ordering)
+[//]: # (NOTA: Ordine alfabetico)
## Librerie
* [Android Support Libraries](http://developer.android.com/tools/support-library/index.html) (Apache License v2)
@@ -61,11 +61,11 @@ Licenza: GPLv3+
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache License v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache License v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Design materiale) (Apache License v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT License)
* [Snackbar](https://github.com/nispok/snackbar) (MIT License)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 License)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache License v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache License v2)
* [ZXing](https://github.com/zxing/zxing) (Apache License v2)
diff --git a/OpenKeychain/src/main/res/raw-it/help_changelog.md b/OpenKeychain/src/main/res/raw-it/help_changelog.md
index e5ebfc8c1..2b5d6b6d4 100644
--- a/OpenKeychain/src/main/res/raw-it/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-it/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTA: Si prega di mettere ogni frase in una propria linea, Transifex mette ogni riga nel proprio campo di traduzione!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Key revocation on key deletion
diff --git a/OpenKeychain/src/main/res/raw-ja/help_about.md b/OpenKeychain/src/main/res/raw-ja/help_about.md
index 17e3e17e3..5748aa299 100644
--- a/OpenKeychain/src/main/res/raw-ja/help_about.md
+++ b/OpenKeychain/src/main/res/raw-ja/help_about.md
@@ -1,8 +1,8 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) は Android における OpenPGP 実装です。
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
ライセンス: GPLv3以降
@@ -61,11 +61,11 @@
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache License v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache License v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT License)
* [Snackbar](https://github.com/nispok/snackbar) (MIT License)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 License)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache License v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache License v2)
* [ZXing](https://github.com/zxing/zxing) (Apache License v2)
diff --git a/OpenKeychain/src/main/res/raw-ja/help_changelog.md b/OpenKeychain/src/main/res/raw-ja/help_changelog.md
index 148a33206..69efc6715 100644
--- a/OpenKeychain/src/main/res/raw-ja/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-ja/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.6
+
+ * 暗号化したバックアップ
+ * 外部セキュリティ監査によるセキュリティ修正
+ * YubiKey NEO 鍵生成ウィザード
+ * 基本的な内部 MIME のサポート
+ * 自動鍵同期
+ * 試験的機能: Github, Twitter アカウントと鍵のリンク
+ * 試験的機能: 語句による鍵検証
+ * 試験的機能: ダークテーマ
+ * API: Version 9
+
## 3.5
* 鍵削除時の鍵の破棄
diff --git a/OpenKeychain/src/main/res/raw-nl/help_about.md b/OpenKeychain/src/main/res/raw-nl/help_about.md
index 5c0bc3327..2c88bed8f 100644
--- a/OpenKeychain/src/main/res/raw-nl/help_about.md
+++ b/OpenKeychain/src/main/res/raw-nl/help_about.md
@@ -1,8 +1,8 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) is een OpenPGP implementatie voor Android.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
Licentie: GPLv3+
@@ -61,11 +61,11 @@ Licentie: GPLv3+
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache licentie v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache licentie v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache licentie v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache licentie v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache licentie v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT licentie)
* [Snackbar](https://github.com/nispok/snackbar) (MIT licentie)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 licentie)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache licentie v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache licentie v2)
* [ZXing](https://github.com/zxing/zxing) (Apache licentie v2)
diff --git a/OpenKeychain/src/main/res/raw-nl/help_changelog.md b/OpenKeychain/src/main/res/raw-nl/help_changelog.md
index d378550c4..772a56c48 100644
--- a/OpenKeychain/src/main/res/raw-nl/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-nl/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Sleutel intrekken bij verwijderen
diff --git a/OpenKeychain/src/main/res/raw-pl/help_about.md b/OpenKeychain/src/main/res/raw-pl/help_about.md
index 7262dfefd..28e0b04c5 100644
--- a/OpenKeychain/src/main/res/raw-pl/help_about.md
+++ b/OpenKeychain/src/main/res/raw-pl/help_about.md
@@ -1,8 +1,8 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) jest implementacją OpenPGP dla Androida.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
Licencja: GPLv3+
@@ -61,11 +61,11 @@ Licencja: GPLv3+
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache License v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache License v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT License)
* [Snackbar](https://github.com/nispok/snackbar) (MIT License)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 License)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache License v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache License v2)
* [ZXing](https://github.com/zxing/zxing) (Apache License v2)
diff --git a/OpenKeychain/src/main/res/raw-pl/help_changelog.md b/OpenKeychain/src/main/res/raw-pl/help_changelog.md
index 11d7975b1..60deb1c48 100644
--- a/OpenKeychain/src/main/res/raw-pl/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-pl/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Key revocation on key deletion
diff --git a/OpenKeychain/src/main/res/raw-ru/help_about.md b/OpenKeychain/src/main/res/raw-ru/help_about.md
index 1243a5d14..6e7e3e832 100644
--- a/OpenKeychain/src/main/res/raw-ru/help_about.md
+++ b/OpenKeychain/src/main/res/raw-ru/help_about.md
@@ -1,8 +1,8 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) это OpenPGP имплементация для ОС Android.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
Лицензия: GPLv3+
@@ -12,14 +12,14 @@
* Dominik Schürmann (Ведущий разработчик)
* Vincent Breitmoser
-## Top Contributors
+## Лучшие разработчики
* Adithya Abraham Philip
* Ash Hughes
* 'mar-v-in'
* 'Thialfihar' (разработчик APG)
* Tim Bray
-## Occasional Contributors
+## Сторонние разработчики
* Art O Cathain
* Brian C. Barnes
* Bahtiar 'kalkin' Gadimov
@@ -61,11 +61,11 @@
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache License v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache License v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT License)
* [Snackbar](https://github.com/nispok/snackbar) (MIT License)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 License)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache License v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache License v2)
* [ZXing](https://github.com/zxing/zxing) (Apache License v2)
diff --git a/OpenKeychain/src/main/res/raw-ru/help_changelog.md b/OpenKeychain/src/main/res/raw-ru/help_changelog.md
index 11d7975b1..60deb1c48 100644
--- a/OpenKeychain/src/main/res/raw-ru/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-ru/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Key revocation on key deletion
diff --git a/OpenKeychain/src/main/res/raw-sl/help_about.md b/OpenKeychain/src/main/res/raw-sl/help_about.md
index 3fe72beef..eae093b37 100644
--- a/OpenKeychain/src/main/res/raw-sl/help_about.md
+++ b/OpenKeychain/src/main/res/raw-sl/help_about.md
@@ -1,8 +1,8 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) je implementacija OpenPGP za Android.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
Licenca: GPLv3+
@@ -61,11 +61,11 @@ Licenca: GPLv3+
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Licenca Apache v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Licenca Apache v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (Licenca MIT)
* [Snackbar](https://github.com/nispok/snackbar) (Licenca MIT)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (Licenca MIT X11)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Licenca Apache v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Licenca Apache v2)
* [ZXing](https://github.com/zxing/zxing) (Licenca Apache v2)
diff --git a/OpenKeychain/src/main/res/raw-sl/help_changelog.md b/OpenKeychain/src/main/res/raw-sl/help_changelog.md
index 11d7975b1..60deb1c48 100644
--- a/OpenKeychain/src/main/res/raw-sl/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-sl/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Key revocation on key deletion
diff --git a/OpenKeychain/src/main/res/raw-sr/help_about.md b/OpenKeychain/src/main/res/raw-sr/help_about.md
index 5bfbbc6ff..d88344739 100644
--- a/OpenKeychain/src/main/res/raw-sr/help_about.md
+++ b/OpenKeychain/src/main/res/raw-sr/help_about.md
@@ -1,8 +1,8 @@
[//]: #
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[Отворени кључарник (OpenKeychain)](http://www.openkeychain.org) је ОпенПГП имплементација за Андроид.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
Лиценца: ГПЛв3+
@@ -61,11 +61,11 @@
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Апачи лиценца в2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Апачи лиценца в2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Апачи лиценца в2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Материјал дизајн) (Апачи лиценца в2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (МИТ лиценца)
* [Snackbar](https://github.com/nispok/snackbar) (МИТ лиценца)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (МИТ Икс11 лиценца)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Апачи лиценца в2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Апачи лиценца в2)
* [ZXing](https://github.com/zxing/zxing) (Апачи лиценца в2)
diff --git a/OpenKeychain/src/main/res/raw-sr/help_changelog.md b/OpenKeychain/src/main/res/raw-sr/help_changelog.md
index 680664a6d..b3a5bad1c 100644
--- a/OpenKeychain/src/main/res/raw-sr/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-sr/help_changelog.md
@@ -1,5 +1,17 @@
[//]: #
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Опозив кључа при брисању кључа
diff --git a/OpenKeychain/src/main/res/raw-sv/help_about.md b/OpenKeychain/src/main/res/raw-sv/help_about.md
index 0fd4713bb..22aae17a1 100644
--- a/OpenKeychain/src/main/res/raw-sv/help_about.md
+++ b/OpenKeychain/src/main/res/raw-sv/help_about.md
@@ -1,8 +1,8 @@
[//]: # (NOTERING: Var vänlig och sätt varje mening på sin egen rad, Transifex sätter varje rad i sitt eget fält för översättningar!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) är en OpenPGP-implementation till Android.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
Licens: GPLv3+
@@ -61,11 +61,11 @@ Licens: GPLv3+
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache License v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache License v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
* [SafeSlinger's bibliotek för utbyte](https://github.com/SafeSlingerProject/exchange-android) (MIT-licens)
* [Snackbar](https://github.com/nispok/snackbar) (MIT License)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11-licens)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache License v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache License v2)
* [ZXing](https://github.com/zxing/zxing) (Apache License v2)
diff --git a/OpenKeychain/src/main/res/raw-sv/help_changelog.md b/OpenKeychain/src/main/res/raw-sv/help_changelog.md
index 2bec6c216..2cc9fa592 100644
--- a/OpenKeychain/src/main/res/raw-sv/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-sv/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTERING: Var vänlig och sätt varje mening på sin egen rad, Transifex sätter varje rad i sitt eget fält för översättningar!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Key revocation on key deletion
diff --git a/OpenKeychain/src/main/res/raw-tr/help_about.md b/OpenKeychain/src/main/res/raw-tr/help_about.md
index 06bed0021..3538e68cc 100644
--- a/OpenKeychain/src/main/res/raw-tr/help_about.md
+++ b/OpenKeychain/src/main/res/raw-tr/help_about.md
@@ -1,8 +1,8 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) is an OpenPGP implementation for Android.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
License: GPLv3+
@@ -61,11 +61,11 @@ License: GPLv3+
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache License v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache License v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT License)
* [Snackbar](https://github.com/nispok/snackbar) (MIT License)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 License)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache License v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache License v2)
* [ZXing](https://github.com/zxing/zxing) (Apache License v2)
diff --git a/OpenKeychain/src/main/res/raw-tr/help_changelog.md b/OpenKeychain/src/main/res/raw-tr/help_changelog.md
index 11d7975b1..60deb1c48 100644
--- a/OpenKeychain/src/main/res/raw-tr/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-tr/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Key revocation on key deletion
diff --git a/OpenKeychain/src/main/res/raw-uk/help_about.md b/OpenKeychain/src/main/res/raw-uk/help_about.md
index 06bed0021..3538e68cc 100644
--- a/OpenKeychain/src/main/res/raw-uk/help_about.md
+++ b/OpenKeychain/src/main/res/raw-uk/help_about.md
@@ -1,8 +1,8 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) is an OpenPGP implementation for Android.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
License: GPLv3+
@@ -61,11 +61,11 @@ License: GPLv3+
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache License v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache License v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT License)
* [Snackbar](https://github.com/nispok/snackbar) (MIT License)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 License)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache License v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache License v2)
* [ZXing](https://github.com/zxing/zxing) (Apache License v2)
diff --git a/OpenKeychain/src/main/res/raw-uk/help_changelog.md b/OpenKeychain/src/main/res/raw-uk/help_changelog.md
index 11d7975b1..60deb1c48 100644
--- a/OpenKeychain/src/main/res/raw-uk/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-uk/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Key revocation on key deletion
diff --git a/OpenKeychain/src/main/res/raw-zh-rTW/help_about.md b/OpenKeychain/src/main/res/raw-zh-rTW/help_about.md
index ed32e0d5d..527539f12 100644
--- a/OpenKeychain/src/main/res/raw-zh-rTW/help_about.md
+++ b/OpenKeychain/src/main/res/raw-zh-rTW/help_about.md
@@ -1,8 +1,8 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org)是一個Android的OpenPGP應用。
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
授權:GPLv3+
@@ -61,11 +61,11 @@
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache License v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache License v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT License)
* [Snackbar](https://github.com/nispok/snackbar) (MIT License)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 License)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache License v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache License v2)
* [ZXing](https://github.com/zxing/zxing) (Apache License v2)
diff --git a/OpenKeychain/src/main/res/raw-zh-rTW/help_changelog.md b/OpenKeychain/src/main/res/raw-zh-rTW/help_changelog.md
index 20f2ef6c5..def50b580 100644
--- a/OpenKeychain/src/main/res/raw-zh-rTW/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-zh-rTW/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
*可以在刪除金鑰時撤銷金鑰
diff --git a/OpenKeychain/src/main/res/raw-zh/help_about.md b/OpenKeychain/src/main/res/raw-zh/help_about.md
index d8bc20016..1600f19ce 100644
--- a/OpenKeychain/src/main/res/raw-zh/help_about.md
+++ b/OpenKeychain/src/main/res/raw-zh/help_about.md
@@ -1,8 +1,8 @@
[//]: # (注意: 请把每个句子放在其本行中, Transifex把每一行放在它自己的位置!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) 是安卓上的一个 OpenPGP 协议实现。
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
许可协议:GPLv3+
@@ -61,11 +61,11 @@
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache 许可证 v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache 许可证 v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache 许可证 v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design)</a> (Apache 许可证 v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT 许可证)
* [Snackbar](https://github.com/nispok/snackbar) (MIT 许可证)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 许可证)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache 许可证 v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache 许可证 v2)
* [ZXing](https://github.com/zxing/zxing) (Apache 许可证 v2)
diff --git a/OpenKeychain/src/main/res/raw-zh/help_changelog.md b/OpenKeychain/src/main/res/raw-zh/help_changelog.md
index 11d7975b1..60deb1c48 100644
--- a/OpenKeychain/src/main/res/raw-zh/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw-zh/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Key revocation on key deletion
diff --git a/OpenKeychain/src/main/res/raw/fp_sentence_adjectives b/OpenKeychain/src/main/res/raw/fp_sentence_adjectives
new file mode 100644
index 000000000..cf8fa4674
--- /dev/null
+++ b/OpenKeychain/src/main/res/raw/fp_sentence_adjectives
@@ -0,0 +1,128 @@
+able
+angry
+bad
+bent
+bitter
+black
+blue
+boiling
+bright
+broken
+brown
+certain
+cheap
+clean
+clear
+cold
+common
+complex
+cruel
+dark
+dead
+dear
+deep
+dirty
+dry
+early
+elastic
+equal
+false
+fat
+feeble
+female
+fertile
+first
+fixed
+flat
+foolish
+free
+full
+future
+general
+good
+great
+green
+grey
+hanging
+happy
+hard
+healthy
+high
+hollow
+kind
+last
+late
+lazy
+left
+like
+living
+long
+loose
+loud
+low
+male
+married
+medical
+mixed
+narrow
+natural
+new
+normal
+old
+open
+past
+poor
+present
+pretty
+private
+public
+quick
+quiet
+ready
+rare
+red
+regular
+right
+rough
+round
+sad
+safe
+same
+second
+secret
+serious
+sharp
+short
+shut
+sick
+simple
+slow
+small
+smooth
+soft
+solid
+sour
+special
+sticky
+stiff
+strange
+strong
+sudden
+sweet
+tall
+thick
+thin
+tight
+tired
+true
+unknown
+violent
+waiting
+warm
+wet
+white
+wide
+wise
+wrong
+yellow
+young
diff --git a/OpenKeychain/src/main/res/raw/fp_sentence_adverbs b/OpenKeychain/src/main/res/raw/fp_sentence_adverbs
new file mode 100644
index 000000000..1d6002387
--- /dev/null
+++ b/OpenKeychain/src/main/res/raw/fp_sentence_adverbs
@@ -0,0 +1,64 @@
+ably
+angrily
+badly
+bitterly
+brightly
+brokenly
+cheaply
+clearly
+coldly
+commonly
+cruelly
+darkly
+dearly
+deeply
+drily
+equally
+falsely
+feebly
+fixedly
+flatly
+freely
+fully
+greatly
+happily
+hardly
+kindly
+lately
+lazily
+loosely
+loudly
+narrowly
+newly
+normally
+openly
+poorly
+prettily
+publicly
+quickly
+quietly
+readily
+rarely
+roughly
+sadly
+safely
+secretly
+sharply
+simply
+slowly
+smoothly
+softly
+solidly
+sourly
+stiffly
+strongly
+suddenly
+sweetly
+thickly
+thinly
+tightly
+tiredly
+truly
+warmly
+widely
+wisely
diff --git a/OpenKeychain/src/main/res/raw/fp_sentence_articles b/OpenKeychain/src/main/res/raw/fp_sentence_articles
new file mode 100644
index 000000000..0604b3d07
--- /dev/null
+++ b/OpenKeychain/src/main/res/raw/fp_sentence_articles
@@ -0,0 +1,8 @@
+her
+his
+my
+our
+that
+the
+this
+your
diff --git a/OpenKeychain/src/main/res/raw/fp_sentence_nouns b/OpenKeychain/src/main/res/raw/fp_sentence_nouns
new file mode 100644
index 000000000..ed4099c31
--- /dev/null
+++ b/OpenKeychain/src/main/res/raw/fp_sentence_nouns
@@ -0,0 +1,512 @@
+account
+air
+amount
+angle
+animal
+answer
+ant
+apple
+arch
+arm
+army
+attack
+attempt
+baby
+back
+bag
+ball
+band
+base
+basin
+basket
+bath
+bed
+bee
+belief
+bell
+berry
+bird
+birth
+bite
+blade
+blood
+blow
+board
+boat
+body
+bone
+book
+boot
+bottle
+box
+boy
+brain
+brake
+branch
+bread
+breath
+brick
+bridge
+brother
+brush
+bucket
+bulb
+burn
+butter
+button
+cake
+camera
+canvas
+car
+card
+cat
+cause
+chain
+chalk
+chance
+change
+cheese
+chest
+chin
+church
+circle
+clock
+cloth
+cloud
+coal
+coat
+collar
+colour
+comb
+comfort
+company
+control
+cook
+copper
+copy
+cord
+cork
+cotton
+cough
+country
+cover
+cow
+crack
+credit
+crime
+crush
+cry
+cup
+current
+curtain
+curve
+cushion
+damage
+danger
+day
+debt
+degree
+design
+desire
+detail
+disease
+disgust
+dog
+door
+doubt
+drain
+drawer
+dress
+drink
+drop
+dust
+ear
+earth
+edge
+effect
+egg
+end
+engine
+error
+event
+example
+expert
+eye
+face
+fact
+fall
+family
+farm
+father
+fear
+feather
+feeling
+fiction
+field
+fight
+finger
+fire
+fish
+flag
+flame
+flight
+floor
+flower
+fly
+fold
+food
+foot
+force
+fork
+form
+fowl
+frame
+friend
+front
+fruit
+garden
+girl
+glass
+glove
+goat
+gold
+grain
+grass
+grip
+group
+growth
+guide
+gun
+hair
+hammer
+hand
+harbour
+harmony
+hat
+hate
+head
+heart
+heat
+history
+hole
+hook
+hope
+horn
+horse
+hour
+house
+humour
+ice
+idea
+impulse
+ink
+insect
+iron
+island
+jelly
+jewel
+join
+journey
+judge
+jump
+kettle
+key
+kick
+kiss
+knee
+knife
+knot
+land
+laugh
+law
+lead
+leaf
+leather
+leg
+letter
+level
+library
+lift
+light
+limit
+line
+linen
+lip
+liquid
+list
+lock
+look
+loss
+love
+machine
+man
+manager
+map
+mark
+market
+mass
+match
+meal
+measure
+meat
+meeting
+memory
+metal
+middle
+milk
+mind
+mine
+minute
+mist
+money
+monkey
+month
+moon
+morning
+mother
+motion
+mouth
+move
+muscle
+music
+nail
+name
+nation
+neck
+need
+needle
+nerve
+net
+news
+night
+noise
+nose
+note
+number
+nut
+offer
+office
+oil
+opinion
+orange
+order
+oven
+owner
+page
+pain
+paint
+paper
+parcel
+part
+paste
+payment
+peace
+pen
+pencil
+person
+picture
+pig
+pin
+pipe
+place
+plane
+plant
+plate
+play
+plough
+pocket
+point
+poison
+polish
+porter
+pot
+potato
+powder
+power
+price
+print
+prison
+process
+produce
+profit
+prose
+protest
+pull
+pump
+purpose
+push
+quality
+rail
+rain
+range
+rat
+rate
+ray
+reason
+receipt
+record
+regret
+request
+respect
+rest
+reward
+rhythm
+rice
+ring
+river
+road
+rod
+roll
+roof
+room
+root
+rub
+rule
+run
+sail
+salt
+sand
+scale
+school
+science
+screw
+sea
+seat
+seed
+self
+sense
+servant
+sex
+shade
+shake
+shame
+sheep
+shelf
+ship
+shirt
+shock
+shoe
+side
+sign
+silk
+silver
+sister
+size
+skin
+skirt
+sky
+sleep
+slip
+slope
+smash
+smell
+smile
+smoke
+snake
+sneeze
+snow
+soap
+society
+sock
+son
+song
+sort
+sound
+soup
+space
+spade
+sponge
+spoon
+spring
+square
+stage
+stamp
+star
+start
+station
+steam
+steel
+stem
+step
+stick
+stitch
+stomach
+stone
+stop
+store
+story
+street
+stretch
+sugar
+summer
+sun
+support
+swim
+system
+table
+tail
+talk
+taste
+tax
+test
+theory
+thing
+thought
+thread
+throat
+thumb
+thunder
+ticket
+time
+tin
+toe
+tongue
+tooth
+top
+touch
+town
+trade
+train
+tray
+tree
+trick
+trouble
+turn
+twist
+unit
+value
+verse
+vessel
+view
+voice
+walk
+wall
+war
+wash
+waste
+watch
+water
+wave
+wax
+way
+weather
+week
+weight
+wheel
+whip
+whistle
+wind
+window
+wine
+wing
+winter
+wire
+woman
+wood
+wool
+word
+work
+worm
+wound
+writing
+year
diff --git a/OpenKeychain/src/main/res/raw/fp_sentence_prepositions b/OpenKeychain/src/main/res/raw/fp_sentence_prepositions
new file mode 100644
index 000000000..fb8206636
--- /dev/null
+++ b/OpenKeychain/src/main/res/raw/fp_sentence_prepositions
@@ -0,0 +1,32 @@
+above
+across
+after
+against
+along
+among
+around
+at
+before
+behind
+below
+beneath
+beside
+between
+beyond
+by
+from
+in
+inside
+into
+near
+on
+outside
+over
+past
+round
+through
+to
+towards
+under
+upon
+with
diff --git a/OpenKeychain/src/main/res/raw/fp_sentence_verbs_i b/OpenKeychain/src/main/res/raw/fp_sentence_verbs_i
new file mode 100644
index 000000000..57602bf17
--- /dev/null
+++ b/OpenKeychain/src/main/res/raw/fp_sentence_verbs_i
@@ -0,0 +1,128 @@
+agrees
+allows
+answers
+arrives
+asks
+is
+becomes
+begins
+believes
+brings
+burns
+buys
+calls
+changes
+chooses
+cleans
+closes
+comes
+compares
+continues
+cooks
+costs
+counts
+cries
+cuts
+dances
+decides
+describes
+destroys
+dies
+does
+drinks
+drives
+eats
+ends
+explains
+falls
+feels
+fights
+fills
+finds
+finishes
+forgets
+forgives
+gets
+gives
+goes
+grows
+hates
+has
+hears
+helps
+hides
+holds
+hurts
+improves
+jumps
+keeps
+kills
+knows
+laughs
+learns
+leaves
+lets
+lies
+listens
+lives
+looks
+loses
+loves
+makes
+meets
+moves
+needs
+occurs
+offers
+opens
+pays
+plays
+prefers
+prepares
+presses
+promises
+pulls
+pushes
+puts
+reads
+receives
+remembers
+repeats
+rests
+returns
+runs
+sees
+sells
+sends
+shouts
+shows
+sings
+sits
+sleeps
+smiles
+speaks
+starts
+stays
+stops
+studies
+suggests
+supports
+takes
+talks
+teaches
+tells
+thinks
+throws
+touches
+travels
+treats
+tries
+turns
+uses
+visits
+walks
+wants
+washes
+wins
+works
+writes
diff --git a/OpenKeychain/src/main/res/raw/fp_sentence_verbs_t b/OpenKeychain/src/main/res/raw/fp_sentence_verbs_t
new file mode 100644
index 000000000..36078bc78
--- /dev/null
+++ b/OpenKeychain/src/main/res/raw/fp_sentence_verbs_t
@@ -0,0 +1,128 @@
+agrees with
+allows
+answers
+arrives at
+asks
+is
+becomes
+begins
+believes
+brings
+burns
+buys
+calls
+changes
+chooses
+cleans
+closes
+comes to
+compares
+continues
+cooks
+costs
+counts
+cries for
+cuts
+dances with
+decides on
+describes
+destroys
+dies for
+does
+drinks
+drives
+eats
+ends
+explains
+falls on
+feels
+fights
+fills
+finds
+finishes
+forgets
+forgives
+gets
+gives
+goes to
+grows
+hates
+has
+hears
+helps
+hides
+holds
+hurts
+improves
+jumps over
+keeps
+kills
+knows
+laughs at
+learns
+leaves
+lets
+lies to
+listens to
+lives with
+looks at
+loses
+loves
+makes
+meets
+moves
+needs
+occurs to
+offers
+opens
+pays
+plays
+prefers
+prepares
+presses
+promises
+pulls
+pushes
+puts
+reads
+receives
+remembers
+repeats
+rests by
+returns
+runs to
+sees
+sells
+sends
+shouts at
+shows
+sings to
+sits by
+sleeps by
+smiles at
+speaks to
+starts
+stays with
+stops
+studies
+suggests
+supports
+takes
+talks to
+teaches
+tells
+thinks of
+throws
+touches
+travels to
+treats
+tries
+turns
+uses
+visits
+walks to
+wants
+washes
+wins
+works for
+writes to
diff --git a/OpenKeychain/src/main/assets/word_confirm_list.txt b/OpenKeychain/src/main/res/raw/fp_word_list
index 080c7ce81..080c7ce81 100644
--- a/OpenKeychain/src/main/assets/word_confirm_list.txt
+++ b/OpenKeychain/src/main/res/raw/fp_word_list
diff --git a/OpenKeychain/src/main/res/raw/help_about.md b/OpenKeychain/src/main/res/raw/help_about.md
index 45d326daa..c5e8ebccf 100644
--- a/OpenKeychain/src/main/res/raw/help_about.md
+++ b/OpenKeychain/src/main/res/raw/help_about.md
@@ -1,8 +1,8 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
-[http://www.openkeychain.org](http://www.openkeychain.org)
+[https://www.openkeychain.org](https://www.openkeychain.org)
-[OpenKeychain](http://www.openkeychain.org) is an OpenPGP implementation for Android.
+[OpenKeychain](https://www.openkeychain.org) is an OpenPGP implementation for Android.
License: GPLv3+
@@ -61,11 +61,11 @@ License: GPLv3+
* [Markdown4J](https://github.com/jdcasey/markdown4j) (Apache License v2)
* [MaterialDrawer](https://github.com/mikepenz/MaterialDrawer) (Apache License v2)
* [MiniDNS](https://github.com/rtreffer/minidns) (Apache License v2)
- * [OkHttp](http://square.github.io/okhttp/) (Apache License v2)
+ * [OkHttp](https://square.github.io/okhttp/) (Apache License v2)
* [PagerSlidingTabStrip](https://github.com/jpardogo/PagerSlidingTabStrip) (Material Design) (Apache License v2)
* [SafeSlinger Exchange library](https://github.com/SafeSlingerProject/exchange-android) (MIT License)
* [Snackbar](https://github.com/nispok/snackbar) (MIT License)
- * [SpongyCastle](http://rtyley.github.com/spongycastle/) (MIT X11 License)
+ * [SpongyCastle](https://rtyley.github.io/spongycastle/) (MIT X11 License)
* [StickyListHeaders](https://github.com/emilsjolander/StickyListHeaders) (Apache License v2)
* [TokenAutoComplete](https://github.com/splitwise/TokenAutoComplete) (Apache License v2)
* [ZXing](https://github.com/zxing/zxing) (Apache License v2)
diff --git a/OpenKeychain/src/main/res/raw/help_changelog.md b/OpenKeychain/src/main/res/raw/help_changelog.md
index d35d52500..b1966cc7f 100644
--- a/OpenKeychain/src/main/res/raw/help_changelog.md
+++ b/OpenKeychain/src/main/res/raw/help_changelog.md
@@ -1,5 +1,17 @@
[//]: # (NOTE: Please put every sentence in its own line, Transifex puts every line in its own translation field!)
+## 3.6
+
+ * Encrypted backups
+ * Security fixes based on external security audit
+ * YubiKey NEO key creation wizard
+ * Basic internal MIME support
+ * Automatic key synchronization
+ * Experimental feature: link keys to Github, Twitter accounts
+ * Experimental feature: key confirmation via phrases
+ * Experimental feature: dark theme
+ * API: Version 9
+
## 3.5
* Key revocation on key deletion
diff --git a/OpenKeychain/src/main/res/values-cs/strings.xml b/OpenKeychain/src/main/res/values-cs/strings.xml
index 6b6bc956b..ed9879ffb 100644
--- a/OpenKeychain/src/main/res/values-cs/strings.xml
+++ b/OpenKeychain/src/main/res/values-cs/strings.xml
@@ -29,7 +29,6 @@
<string name="title_exchange_keys">Vyměnit klíče</string>
<string name="title_advanced_key_info">Pokročilé informace</string>
<string name="title_delete_secret_key">Smazat Váš klíč \'%s\'?</string>
- <string name="title_export_log">Exportovat log</string>
<string name="title_manage_my_keys">Spravovat klíče</string>
<!--section-->
<string name="section_user_ids">Identity</string>
@@ -37,9 +36,7 @@
<string name="section_linked_system_contact">Propojený kontakt v systému</string>
<string name="section_should_you_trust">Důvěřujete tomuto klíči?</string>
<string name="section_proof_details">Doložit ověření</string>
- <string name="section_cloud_evidence">Doložení z cloudu</string>
<string name="section_keys">Podklíče</string>
- <string name="section_cloud_search">Vyhledávání v Cloud službě</string>
<string name="section_certify">Potvrdit</string>
<string name="section_actions">Akce</string>
<string name="section_share_key">Klíč</string>
@@ -61,12 +58,9 @@
<string name="btn_back">Zpět</string>
<string name="btn_no">Ne</string>
<string name="btn_match">Otisky souhlasí</string>
- <string name="btn_share_encrypted_signed">Zašifrovat a sdílet text</string>
- <string name="btn_copy_encrypted_signed">Zašifrovat a zkopírovat text</string>
<string name="btn_view_cert_key">Zobrazit klíč certifikátu</string>
<string name="btn_create_key">Vytvořit klíč</string>
<string name="btn_add_files">Přidat soubor(y)</string>
- <string name="btn_share_decrypted_text">Sdílet dešifrovaný text</string>
<string name="btn_copy_decrypted_text">Kopírovat dešifrovaný text</string>
<string name="btn_encrypt_files">Zašifrovat soubory</string>
<string name="btn_encrypt_text">Zašifrovat text</string>
@@ -88,8 +82,6 @@
<string name="menu_export_all_keys">Exportovat všechny klíče</string>
<string name="menu_update_all_keys">Aktualizovat všechny klíče</string>
<string name="menu_advanced">Pokročilá informace</string>
- <string name="menu_certify_fingerprint">Potvrdit porovnáním otisků</string>
- <string name="menu_export_log">Exportovat log</string>
<!--label-->
<string name="label_message">Text</string>
<string name="label_file">Soubor</string>
@@ -105,9 +97,7 @@
<string name="label_file_ascii_armor">Povolit ASCII armor</string>
<string name="label_write_version_header">Dát ostatním vědět, že používáte OpenKeychain</string>
<string name="label_write_version_header_summary">Zapisovat \'OpenKeychain v2.7\' do OpenPGP podpisů, šifrovaného textu a exportovaných klíčů</string>
- <string name="label_use_default_yubikey_pin">Použít výchozí YubiKey PIN</string>
<string name="label_use_num_keypad_for_yubikey_pin">Použít numerickou klávesnici pro YubiKey PIN</string>
- <string name="label_label_use_default_yubikey_pin_summary">Používá základní PIN (123456) pro přístup k YubiKey přes NFC</string>
<string name="label_to">Zašifrovat pro:</string>
<string name="label_delete_after_encryption">Smazat soubory po zašifrování</string>
<string name="label_delete_after_decryption">Smazat po rozšifrování</string>
@@ -128,15 +118,12 @@
<string name="label_name">Jméno</string>
<string name="label_comment">Komentář</string>
<string name="label_email">Email</string>
- <string name="label_send_key">Synchronizovat s cloudem</string>
<string name="label_fingerprint">Otisk</string>
<string name="expiry_date_dialog_title">Nastavit datum expirace</string>
<string name="label_preferred">upřednostněno</string>
<string name="label_enable_compression">Zapnout kompresi</string>
<string name="label_encrypt_filenames">Zašifrovat jména souborů</string>
<string name="label_hidden_recipients">Skrýt příjemce</string>
- <string name="label_verify_keyserver">Ověřit keyserver</string>
- <string name="label_enter_keyserver_url">Zadejte URL keyserveru</string>
<string name="pref_keyserver">OpenPGP keyserver</string>
<string name="pref_keyserver_summary">Vyhledat klíče na vybraném OpenPGP keyserveru (protokol HKP)</string>
<string name="pref_keybase">keybase.io</string>
@@ -147,8 +134,6 @@
<!--OrbotHelper strings-->
<!--InstallDialogFragment strings-->
<!--StartOrbotDialogFragment strings-->
- <string name="user_id_no_name">&lt;beze jména&gt;</string>
- <string name="none">&lt;žádný&gt;</string>
<plurals name="n_keys">
<item quantity="one">1 klíč</item>
<item quantity="few">%d klíče</item>
@@ -192,7 +177,6 @@
<string name="no_filemanager_installed">Není nainstalován žádný compatibilní správce souborů.</string>
<string name="passphrases_do_not_match">Hesla se neschodují.</string>
<string name="passphrase_must_not_be_empty">Zadejte heslo.</string>
- <string name="passphrase_for_symmetric_encryption">Symetrická šifra.</string>
<string name="passphrase_for">Zadejte heslo pro \'%s\'</string>
<string name="pin_for">Zadejte PIN pro \'%s\'</string>
<string name="yubikey_pin_for">Zadejte PIN pro přístup k YubiKey pro \'%s\'</string>
@@ -205,7 +189,6 @@
<string name="specify_file_to_encrypt_to">Prosím specifikujte do kterého souboru zašifrovat.\nVAROVÁNÍ: Pokud soubor již existuje, bude přepsán.</string>
<string name="specify_file_to_decrypt_to">Prosím specifikujte do kterého souboru rozšifrovat.\nVAROVÁNÍ: Pokud soubor již existuje, bude přepsán.</string>
<string name="key_deletion_confirmation_multi">Opravdu chcete smazat všechny vybrané soubory?</string>
- <string name="secret_key_deletion_confirmation">Po smazání již nebudete schopni přečíst zprávy zašifrované tímto klíčem a stratíte všechny potvrzení udělané tímto klíčem!</string>
<string name="public_key_deletetion_confirmation">Smazat klíč \'%s\'?</string>
<string name="also_export_secret_keys">Zárověň exportovat tajný klíč</string>
<string name="reinstall_openkeychain">Narazili jste na známou chybu v Androidu. Přeinstalujte prosím OpenKeychain pokud chcete své propojit kontakty s klíči.</string>
@@ -214,13 +197,11 @@
<string name="no_keys_exported">Žádný kláč pro export.</string>
<string name="key_creation_el_gamal_info">Žádný: pouze podklíče podporují ElGamal.</string>
<string name="key_not_found">Nemohu najít klíč %08X.</string>
- <string name="specify_file_to_export_log_to">Prosím specifikujte do kterého souboru exportovat.\nVAROVÁNÍ: Pokud soubor již existuje, bude přepsán.</string>
<string name="list_empty">Seznam je prázný!</string>
<string name="nfc_successful">Úspěšně odeslaný klíč pomocí NFC Beam!</string>
<string name="key_copied_to_clipboard">Klíč byl zkopírován do schránky!</string>
<string name="fingerprint_copied_to_clipboard">Fingerprint byl zkopírován do schránky!</string>
<string name="select_key_to_certify">Prosím vyberte klíč, který bude použit k potvrzení!</string>
- <string name="key_too_big_for_sharing">Klíč je příliš velký aby byl sdílen pomocí této metody!</string>
<string name="text_copied_to_clipboard">Text byl zkopírován do schránky!</string>
<!--errors
no punctuation, all lowercase,
@@ -301,8 +282,8 @@
<string name="progress_encrypting">šifruji data...</string>
<string name="progress_decrypting">dešifruji data...</string>
<string name="progress_preparing_signature">připravuji podpis...</string>
- <string name="progress_generating_signature">generuji podpis...</string>
<string name="progress_processing_signature">zpracovávám podpis...</string>
+ <string name="progress_generating_signature">generuji podpis...</string>
<string name="progress_verifying_signature">verifikuji podpis...</string>
<string name="progress_signing">podepisuji...</string>
<string name="progress_certifying">ověřuji...</string>
@@ -314,10 +295,6 @@
<string name="progress_deleting">mažu klíče...</string>
<!--action strings-->
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -346,7 +323,6 @@
<string name="help_about_version">Verze:</string>
<!--Import-->
<string name="import_tab_keyserver">Keyserver</string>
- <string name="import_tab_cloud">Hledat v cloudu</string>
<string name="import_tab_direct">Soubor/schránka</string>
<string name="import_tab_qr_code">QR kód/NFC</string>
<string name="import_import">Importovat vybrané klíče</string>
@@ -355,11 +331,6 @@
<!--Import from URL-->
<!--Generic result toast-->
<!--Import result toast-->
- <plurals name="import_keys_added_and_updated_1">
- <item quantity="one">Klíč úspěšně importován</item>
- <item quantity="few">Úspěšně importováno %1$d klíče</item>
- <item quantity="other">Úspěšně importováno %1$d klíčů</item>
- </plurals>
<plurals name="import_error">
<item quantity="one">Import selhal!</item>
<item quantity="few">Import %d klíčů selhal!</item>
@@ -412,7 +383,6 @@
</plurals>
<string name="key_list_empty_text1">Žádný klíč nenalezen!</string>
<string name="key_list_filter_show_all">Zobrazit všechny klíče</string>
- <string name="key_list_filter_show_certified">Zobrazit puze ověřené klíče</string>
<!--Key view-->
<string name="key_view_action_edit">Editovat klíč</string>
<string name="key_view_action_encrypt">Zašifrovat text</string>
@@ -429,23 +399,11 @@
<string name="key_view_tab_keybase">Keybase.io</string>
<string name="user_id_info_revoked_title">Zneplatněno</string>
<string name="user_id_info_revoked_text">Tato identity byla zneplatněna vlastníkem klíče. Klíč již není platný.</string>
- <string name="user_id_info_certified_title">Ověřeno</string>
- <string name="user_id_info_certified_text">Tato identita byla vámi ověřena</string>
- <string name="user_id_info_uncertified_title">Neověřeno</string>
- <string name="user_id_info_uncertified_text">Tato identita nebyla ještě ověřena. Nemůžete si být jisti, že identita skutečně odpovídá konkrétní osobě.</string>
<string name="user_id_info_invalid_title">Neplatná</string>
<string name="user_id_info_invalid_text">S touto identitou je něco v nepořádku!</string>
<!--Key trust-->
- <string name="key_trust_already_verified">Již jste tento klíč potvrdili!</string>
- <string name="key_trust_it_is_yours">Toto je jeden z vašich klíčů!</string>
- <string name="key_trust_maybe">Tento klíč je buďto zneplatněný nebo vypršel\nNepotvrdili jste ho, ale můžete mu začít důvěřovat.</string>
- <string name="key_trust_revoked">Klíč byl zneplatněn vlastníkem. Neměli byste mu důvěřovat.</string>
- <string name="key_trust_expired">Tento klíč vypršel. Neměli byste mu důvěřovat.</string>
- <string name="key_trust_old_keys">Rozšifrovat staré zprávy pocházející z doby kdy klíč byl ještě platný, může být v pořádku.</string>
- <string name="key_trust_no_cloud_evidence">O důvěryhodnosti tohoto klíče není možné získat důkaz z cloudu.</string>
<string name="key_trust_start_cloud_search">Vyhledat</string>
<string name="key_trust_results_prefix">Keybase.io nabízí “důkazy” které tvrdí, že vlastníkem tohoto klíče je: </string>
- <string name="key_trust_header_text">Poznámka: Keybase.io důkazy jsou experimentální fíčura OpenKeychainu. Doporučujeme vám navíc potvrdit je pomocí naskenování QR kódu nebo si vyměnit klíče pomocí NFC.</string>
<!--keybase proof stuff-->
<string name="keybase_a_post">Příspěvek</string>
<string name="keybase_twitter_proof">tweet</string>
@@ -471,7 +429,6 @@
<string name="edit_key_error_add_identity">Přidejte alespoň jednu identitu!</string>
<string name="edit_key_error_add_subkey">Přidejte alespoň jeden podklíč!</string>
<!--Create key-->
- <string name="create_key_upload">Synchronizovat s cloudem</string>
<string name="create_key_empty">Toto pole je vyžadováno</string>
<string name="create_key_passphrases_not_equal">Hesla se neschodují.</string>
<string name="create_key_final_text">Zadali jste následující identitu:</string>
@@ -496,10 +453,8 @@
<string name="view_key_fragment_no_system_contact">&lt;žádný&gt;</string>
<!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Přidat keyserver</string>
- <string name="add_keyserver_verified">Keyserver ověřen!</string>
<string name="add_keyserver_without_verification">Keyserver přidán bez verifikace.</string>
<string name="add_keyserver_invalid_url">Neplatná URL!</string>
- <string name="add_keyserver_connection_failed">Nepodařilo se připojit ke key severu. Prosím ověřte URL a vaše připojení k internetu.</string>
<!--Navigation Drawer-->
<string name="nav_keys">Klíče</string>
<string name="nav_encrypt_decrypt">Zašifrovat/Dešifrovat</string>
@@ -556,7 +511,6 @@
<string name="msg_ip_master_flags_xxxa">Hlavní příznaky: přihlášení</string>
<string name="msg_ip_master_flags_xxxx">Hlavní příznaky: žádné</string>
<string name="msg_ip_merge_public">Slučuji importovaná data do existující veřejné klíčenky</string>
- <string name="msg_ip_merge_secret">Slučuji importovaná data do existující veřejné klíčenky</string>
<string name="msg_ip_subkey">Zpracovávám podklíč %s</string>
<string name="msg_ip_subkey_expired">Podklíč vypršel %s</string>
<string name="msg_ip_subkey_expires">Podklíč vypršel %s</string>
@@ -608,7 +562,6 @@
<string name="msg_is_importing_subkeys">Zpracovávám tajné podklíče</string>
<string name="msg_is_error_io_exc">Chyba kódování klíčenky</string>
<string name="msg_is_merge_public">Slučuji importovaná data do existující veřejné klíčenky</string>
- <string name="msg_is_merge_secret">Slučuji importovaná data do existující veřejné klíčenky</string>
<string name="msg_is_pubring_generate">Vytvářím veřejnou klíčenku z tajné</string>
<string name="msg_is_subkey_nonexistent">Podklíč %s není k dispozici v tajném klíči</string>
<string name="msg_is_subkey_ok">Označen tajný podklíč %s jako že je k dispozici</string>
@@ -647,9 +600,10 @@
<!--Messages for VerifySignedLiteralData operation-->
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Linked Identity verification-->
<string name="msg_acc_saved">Účet uložen</string>
<!--Messages for Keybase Verification operation-->
- <!--Messages for Export Log operation-->
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<!--Keyserver sync-->
<!--First Time-->
@@ -658,7 +612,6 @@
<!--unsorted-->
<string name="section_cert">Detaily certifikátu</string>
<string name="label_user_id">Identita</string>
- <string name="unknown_uid">&lt;neznámý&gt;</string>
<string name="empty_certs">Žádné certifikáty pro tento klíč</string>
<string name="label_revocation">Důvod revokace</string>
<string name="label_cert_type">Typ</string>
@@ -677,4 +630,5 @@
<!--TODO: rename all the things!-->
<!--<string name="enter_passphrase_twice">Enter password twice</string>-->
<!--<string name="nfc_text">Please place a NFC tag near your device</string>-->
+ <!--Other Linked Identity strings-->
</resources>
diff --git a/OpenKeychain/src/main/res/values-de/strings.xml b/OpenKeychain/src/main/res/values-de/strings.xml
index 291ebf238..42c7cb790 100644
--- a/OpenKeychain/src/main/res/values-de/strings.xml
+++ b/OpenKeychain/src/main/res/values-de/strings.xml
@@ -9,6 +9,7 @@
<string name="title_decrypt">Entschlüsseln</string>
<string name="title_add_subkey">Unterschlüssel hinzufügen</string>
<string name="title_edit_key">Schlüssel bearbeiten</string>
+ <string name="title_linked_create">Eine Verknüpfte-Identität erzeugen</string>
<string name="title_preferences">Einstellungen</string>
<string name="title_api_registered_apps">Apps</string>
<string name="title_key_server_preference">OpenPGP-Schlüsselserver</string>
@@ -27,25 +28,29 @@
<string name="title_certify_key">Schlüssel bestätigen</string>
<string name="title_key_details">Schlüsseldetails</string>
<string name="title_help">Hilfe</string>
- <string name="title_log_display">Log</string>
+ <string name="title_log_display">Protokoll</string>
<string name="title_exchange_keys">Schlüssel austauschen</string>
<string name="title_advanced_key_info">Erweiterte Informationen</string>
<string name="title_delete_secret_key">DEINEN Schlüssel \'%s\' löschen?</string>
- <string name="title_export_log">Log exportieren</string>
<string name="title_manage_my_keys">Meine Schlüssel verwalten</string>
<!--section-->
<string name="section_user_ids">Identitäten</string>
<string name="section_yubikey">YubiKey</string>
<string name="section_linked_system_contact">Verknüpfter Systemkontakt</string>
+ <string name="section_keybase_proofs">Keybase.io-Nachweise</string>
<string name="section_should_you_trust">Sollte ich diesem Schlüssel vertrauen?</string>
<string name="section_proof_details">Nachweis verifizieren</string>
- <string name="section_cloud_evidence">Nachweise aus der Cloud</string>
<string name="section_keys">Unterschlüssel</string>
- <string name="section_cloud_search">Cloudsuche</string>
- <string name="section_passphrase_cache">Passwort/PIN-Handhabung</string>
- <string name="section_proxy_settings">Proxy-Einstellungen</string>
+ <string name="section_cloud_search">Schlüsselsuche</string>
+ <string name="section_cloud_search_summary">Schlüsselserver, Keybase.io</string>
+ <string name="section_passphrase_cache">Passwörter und PINs</string>
+ <string name="section_passphrase_cache_summary">Bedienung, Benutzeroberfläche, Merkdauer</string>
+ <string name="section_proxy_settings">Netzwerkanonymität</string>
+ <string name="section_proxy_settings_summary">Tor, Proxyeinstellungen</string>
<string name="section_gui">Oberfläche</string>
- <string name="section_sync_settings">Synchronisierungseinstellungen</string>
+ <string name="section_sync_settings">Synchronisierung</string>
+ <string name="section_sync_settings_summary">Automatische Schlüsselaktualisierung, Kontaktverknüpfung</string>
+ <string name="section_experimental_features">Experimentelle Funktionen</string>
<string name="section_certify">Bestätigen</string>
<string name="section_actions">Aktionen</string>
<string name="section_share_key">Schlüssel</string>
@@ -61,7 +66,7 @@
<string name="btn_encrypt_save_file">Datei verschlüsseln und speichern</string>
<string name="btn_save_file">Datei speichern</string>
<string name="btn_save">Speichern</string>
- <string name="btn_view_log">Log anzeigen</string>
+ <string name="btn_view_log">Protokoll anzeigen</string>
<string name="btn_do_not_save">Abbrechen</string>
<string name="btn_delete">Löschen</string>
<string name="btn_no_date">Kein Ablaufdatum</string>
@@ -71,12 +76,11 @@
<string name="btn_back">Zurück</string>
<string name="btn_no">Nein</string>
<string name="btn_match">Fingerabdrücke stimmen überein</string>
- <string name="btn_share_encrypted_signed">Text verschlüsseln und teilen</string>
- <string name="btn_copy_encrypted_signed">Text verschlüsseln und kopieren</string>
+ <string name="btn_share_encrypted_signed">Text verschlüsseln/signieren und teilen</string>
+ <string name="btn_copy_encrypted_signed">Text verschlüsseln/signieren und kopieren</string>
<string name="btn_view_cert_key">Beglaubigungsschlüssel anzeigen</string>
<string name="btn_create_key">Schlüssel erzeugen</string>
<string name="btn_add_files">Datei(en) hinzufügen</string>
- <string name="btn_share_decrypted_text">Entschlüsselten Text teilen</string>
<string name="btn_copy_decrypted_text">Entschlüsselten Text kopieren</string>
<string name="btn_decrypt_clipboard">Aus Zwischenablage lesen</string>
<string name="btn_decrypt_files">Datei auswählen</string>
@@ -90,7 +94,6 @@
<!--menu-->
<string name="menu_preferences">Einstellungen</string>
<string name="menu_help">Hilfe</string>
- <string name="menu_export_key">Backup erstellen</string>
<string name="menu_delete_key">Schlüssel löschen</string>
<string name="menu_manage_keys">Meine Schlüssel verwalten</string>
<string name="menu_search">Suchen</string>
@@ -102,7 +105,6 @@
<string name="menu_update_all_keys">Alle Schlüssel aktualisieren</string>
<string name="menu_advanced">Erweiterte Informationen</string>
<string name="menu_certify_fingerprint">Durch Vergleich der Fingerabdrücke bestätigen</string>
- <string name="menu_export_log">Log exportieren</string>
<string name="menu_keyserver_add">Hinzufügen</string>
<!--label-->
<string name="label_message">Text</string>
@@ -119,9 +121,7 @@
<string name="label_file_ascii_armor">Aktiviere ASCII Armor</string>
<string name="label_write_version_header">Lass andere wissen dass du OpenKeychain nutzt</string>
<string name="label_write_version_header_summary">Fügt \'OpenKeychain v2.7\' zu OpenPGP-Signaturen, Daten und exportierten Schlüsseln hinzu</string>
- <string name="label_use_default_yubikey_pin">Voreingestellte YubiKey-PIN verwenden</string>
<string name="label_use_num_keypad_for_yubikey_pin">Zifferntastatur für YubiKey-PINs verwenden</string>
- <string name="label_label_use_default_yubikey_pin_summary">Verwendet die voreingestellte PIN (123456) um YubiKeys über NFC anzusprechen</string>
<string name="label_asymmetric_from">Signiere mit:</string>
<string name="label_to">Verschlüsselt an:</string>
<string name="label_delete_after_encryption">Dateien nach Verschlüsselung löschen</string>
@@ -145,9 +145,9 @@
<string name="label_name">Name</string>
<string name="label_comment">Kommentar</string>
<string name="label_email">E-Mail</string>
- <string name="label_send_key">Mit der Cloud synchronisieren</string>
+ <string name="label_send_key">Mit dem Internet synchronisieren</string>
<string name="label_fingerprint">Fingerabdruck</string>
- <string name="expiry_date_dialog_title">Ablaufdatum festsetzen</string>
+ <string name="expiry_date_dialog_title">Ablaufdatum festlegen</string>
<string name="label_keyservers_title">Schlüsselserver</string>
<string name="label_keyserver_settings_hint">Ziehen zum Ändern der Sortierung, tippen zum Bearbeiten/Löschen</string>
<string name="label_selected_keyserver_title">Ausgewählter Schlüsselserver</string>
@@ -155,22 +155,27 @@
<string name="label_enable_compression">Komprimierung aktivieren</string>
<string name="label_encrypt_filenames">Dateinamen verschlüsseln</string>
<string name="label_hidden_recipients">Empfänger verbergen</string>
- <string name="label_verify_keyserver">Schlüsselserver verifizieren</string>
- <string name="label_enter_keyserver_url">Schlüsselserver-URL eingeben</string>
<string name="label_keyserver_dialog_delete">Schlüsselserver löschen</string>
<string name="label_theme">Design</string>
<string name="pref_keyserver">OpenPGP-Schlüsselserver</string>
<string name="pref_keyserver_summary">Schlüssel auf ausgewählten OpenPGP-Schlüsselservern suchen (HKP-Protokoll)</string>
- <string name="pref_keybase">keybase.io</string>
- <string name="pref_keybase_summary">Schlüssel auf keybase.io suchen</string>
+ <string name="pref_keybase">Keybase.io</string>
+ <string name="pref_keybase_summary">Schlüssel auf Keybase.io suchen</string>
<string name="label_sync_settings_keyserver_title">Schlüssel automatisch aktualisieren</string>
<string name="label_sync_settings_keyserver_summary_on">Schlüssel, die älter als eine Woche sind, werden vom ausgewählten Schlüsselserver aktualisiert</string>
<string name="label_sync_settings_keyserver_summary_off">Schlüssel werden nicht automatisch aktualisiert</string>
- <string name="label_sync_settings_contacts_title">Kontakte mit Schlüsseln synchronisieren</string>
- <string name="label_sync_settings_contacts_summary_on">Verknüpfungen zwischen Schlüsseln und Kontakten mit übereinstimmenden E-Mail-Adressen, erfolgen komplett offline</string>
+ <string name="label_sync_settings_contacts_title">Schlüssel mit Kontakten verknüpfen</string>
+ <string name="label_sync_settings_contacts_summary_on">Schlüssel basierend auf Namen und E-Mail-Adressen mit Kontakten verknüpfen. Das alles findet komplett offline auf deinem Gerät statt.</string>
<string name="label_sync_settings_contacts_summary_off">Neue Schlüssel werden nicht mit Kontakten verknüpft</string>
<!--label shown in Android settings under the OpenKeychain account-->
<string name="keyserver_sync_settings_title">Schlüssel automatisch aktualisieren</string>
+ <string name="label_experimental_settings_desc_title">Warnung</string>
+ <string name="label_experimental_settings_desc_summary">Diese Funktionen sind noch nicht final oder das Ergebnis von Benutzererfahrungs-/Sicherheitsuntersuchungen. Verlasse dich daher nicht auf deren Sicherheit und melde uns bitte keine Probleme die dir begegnen!</string>
+ <string name="label_experimental_settings_linked_identities_title">Verknüpfte-Identitäten</string>
+ <string name="label_experimental_settings_linked_identities_summary">Schlüssel mit Twitter, GitHub, Webseiten oder DNS verknüpfen (ähnlich wie bei Keybase.io, aber dezentralisiert)</string>
+ <string name="label_experimental_settings_keybase_title">Keybase.io-Nachweise</string>
+ <string name="label_experimental_settings_keybase_summary">Keybase.io für Schlüsselnachweise kontaktieren und diese jedesmal zeigen, wenn ein Schlüssel angezeigt wird</string>
+ <string name="label_experimental_settings_theme_summary">(Die Symbole und viele Bildschirme sind noch nicht an das dunkle Design angepasst)</string>
<!--Proxy Preferences-->
<string name="pref_proxy_tor_title">Tor aktivieren</string>
<string name="pref_proxy_tor_summary">Orbot muss installiert sein</string>
@@ -184,22 +189,18 @@
<string name="pref_proxy_type_choice_http">HTTP</string>
<string name="pref_proxy_type_choice_socks">SOCKS</string>
<!--OrbotHelper strings-->
- <string name="orbot_ignore_tor">Tor wird nicht verwendet</string>
<!--InstallDialogFragment strings-->
<string name="orbot_install_dialog_title">Orbot installieren, um Tor zu nutzen?</string>
<string name="orbot_install_dialog_install">Installieren</string>
<string name="orbot_install_dialog_content">Du musst Orbot installiert und aktiviert haben, um Netzwerverkehr hindurchleiten zu können. Möchtest du es installieren?</string>
<string name="orbot_install_dialog_cancel">Abbrechen</string>
- <string name="orbot_install_dialog_ignore_tor">Tor nicht verwendet</string>
<!--StartOrbotDialogFragment strings-->
<string name="orbot_start_dialog_title">Orbot starten?</string>
- <string name="orbot_start_dialog_content">Orbot scheint nicht zu laufen. Möchtest du es starten und mit Tor verbinden?</string>
<string name="orbot_start_btn">Orbot starten</string>
<string name="orbot_start_dialog_start">Orbot starten</string>
<string name="orbot_start_dialog_cancel">Abbrechen</string>
- <string name="orbot_start_dialog_ignore_tor">Tor nicht verwendet</string>
- <string name="user_id_no_name">&lt;kein Name&gt;</string>
- <string name="none">&lt;keine&gt;</string>
+ <string name="user_id_no_name"><![CDATA[<kein Name>]]></string>
+ <string name="none"><![CDATA[<keine>]]></string>
<plurals name="n_keys">
<item quantity="one">1 Schlüssel</item>
<item quantity="other">%d Schlüssel</item>
@@ -223,6 +224,7 @@
<string name="choice_4hours">4 Stunden</string>
<string name="choice_8hours">8 Stunden</string>
<string name="choice_forever">für immer</string>
+ <string name="choice_select_cert">Einen Schlüssel auswählen</string>
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
@@ -243,7 +245,6 @@
<string name="no_filemanager_installed">Kein passender Dateimanager installiert.</string>
<string name="passphrases_do_not_match">Die Passwörter stimmten nicht überein.</string>
<string name="passphrase_must_not_be_empty">Bitte ein Passwort eingeben.</string>
- <string name="passphrase_for_symmetric_encryption">Symmetrische Verschlüsselung.</string>
<string name="passphrase_for">Passwort für \'%s\' eingeben</string>
<string name="pin_for">PIN für \'%s\' eingeben</string>
<string name="yubikey_pin_for">PIN des YubiKeys für \'%s\' eingeben</string>
@@ -266,7 +267,6 @@
<string name="specify_backup_dest_secret_single">Ein vollständiges Backup deiner Schlüssel wird erstellt, bitte wähle eine Zieldatei.\nWARNUNG: Die Datei wird überschrieben, falls sie schon existiert!</string>
<string name="specify_backup_dest_secret">Ein vollständiges Backup aller Schlüssel, inklusive deiner eigenen, wird erstellt, bitte wähle eine Zieldatei.\nWARNUNG: Die Datei wird überschrieben, falls sie schon existiert!</string>
<string name="key_deletion_confirmation_multi">Möchtest du wirklich alle ausgewählten Schlüssel löschen?</string>
- <string name="secret_key_deletion_confirmation">Nach dem Löschen wird es dir nicht mehr möglich sein mit diesem Schlüssel verschlüsselte Nachrichten zu lesen, zudem wirst du alle damit getätigten Bestätigungen verlieren!</string>
<string name="public_key_deletetion_confirmation">Schlüssel \'%s\' löschen?</string>
<string name="also_export_secret_keys">Exportiere auch private Schlüssel</string>
<string name="reinstall_openkeychain">Es ist ein bekannter Fehler im Zusammenhang mit Android aufgetreten. Bitte installiere OpenKeychain erneut, wenn du deine Kontakte mit Schlüsseln verknüpfen willst.</string>
@@ -275,7 +275,6 @@
<string name="no_keys_exported">Keine Schlüssel exportiert.</string>
<string name="key_creation_el_gamal_info">Beachte: Nur Unterschlüssel unterstützen ElGamal.</string>
<string name="key_not_found">Schlüssel %08X konnte nicht gefunden werden.</string>
- <string name="specify_file_to_export_log_to">Bitte Datei zum Exportieren angeben.\nWARNUNG: Die Datei wird überschrieben, falls sie bereits existiert.</string>
<plurals name="bad_keys_encountered">
<item quantity="one">%d fehlerhafter privater Schlüssel ignoriert. Evtl. wurde er mit folgender Option exportiert:\n --export-secret-subkeys\nUnbedingt mit dieser Option exportieren:\n --export-secret-keys</item>
<item quantity="other">%d fehlerhafte private Schlüssel ignoriert. Evtl. wurden sie mit folgender Option exportiert:\n --export-secret-subkeys\nUnbedingt mit dieser Option exportieren:\n --export-secret-keys</item>
@@ -285,7 +284,6 @@
<string name="key_copied_to_clipboard">Schlüssel wurde in die Zwischenablage kopiert!</string>
<string name="fingerprint_copied_to_clipboard">Fingerabdruck wurde in die Zwischenablage kopiert!</string>
<string name="select_key_to_certify">Bitte wähle einen Schlüssel aus, der für die Bestätigung genutzt werden soll!</string>
- <string name="key_too_big_for_sharing">Schlüssel ist zu groß um so geteilt zu werden!</string>
<string name="text_copied_to_clipboard">Text wurde in die Zwischenablage kopiert!</string>
<!--errors
no punctuation, all lowercase,
@@ -373,8 +371,8 @@
<string name="progress_encrypting">Daten werden verschlüsselt…</string>
<string name="progress_decrypting">Daten werden entschlüsselt…</string>
<string name="progress_preparing_signature">Signatur wird vorbereitet…</string>
- <string name="progress_generating_signature">Signatur wird erzeugt…</string>
<string name="progress_processing_signature">Signatur wird verarbeitet…</string>
+ <string name="progress_generating_signature">Signatur wird erzeugt…</string>
<string name="progress_verifying_signature">Signatur wird verifiziert…</string>
<string name="progress_signing">Wird signiert…</string>
<string name="progress_certifying">Wird beglaubigt...</string>
@@ -383,18 +381,13 @@
<string name="progress_decompressing_data">Daten werden entpackt…</string>
<string name="progress_verifying_integrity">Integrität wird verifiziert…</string>
<string name="progress_deleting_securely">\'%s\' wird sicher gelöscht…</string>
- <string name="progress_deleting">Lösche Schlüssel…</string>
- <string name="progress_con_saving">Zusammenführung: Sichere in den Zwischenspeicher...</string>
- <string name="progress_con_reimport">Zusammenführung: Reimportiere...</string>
- <string name="progress_verifying_keyserver_url">Schlüsselserver wird verifiziert…</string>
+ <string name="progress_deleting">Schlüssel werden gelöscht…</string>
+ <string name="progress_con_saving">Zusammenführung: Wird in den Zwischenspeicher gesichert...</string>
+ <string name="progress_con_reimport">Zusammenführung: Wird reimportiert...</string>
<string name="progress_starting_orbot">Orbot wird gestartet…</string>
<!--action strings-->
<string name="hint_cloud_search_hint">Via Name, E-Mail suchen...</string>
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -424,7 +417,7 @@
<string name="help_about_version">Version:</string>
<!--Import-->
<string name="import_tab_keyserver">Schlüsselserver</string>
- <string name="import_tab_cloud">In der Cloud suchen</string>
+ <string name="import_tab_cloud">Schlüsselsuche</string>
<string name="import_tab_direct">Datei/Zwischenablage</string>
<string name="import_tab_qr_code">QR-Code/NFC</string>
<string name="import_import">Ausgewählte Schlüssel importieren</string>
@@ -441,34 +434,34 @@
<string name="with_cancelled">, bis abgebrochen wurde</string>
<!--Import result toast-->
<plurals name="import_keys_added_and_updated_1">
- <item quantity="one">Schlüssel wurde erfolgreich importiert</item>
+ <item quantity="one">Ein Schlüssel wurde erfolgreich importiert</item>
<item quantity="other">%1$d Schlüssel wurden erfolgreich importiert</item>
</plurals>
<plurals name="import_keys_added_and_updated_2">
- <item quantity="one">und Schlüssel aktualisiert%2$s.</item>
+ <item quantity="one">und ein Schlüssel aktualisiert%2$s.</item>
<item quantity="other">und %1$d Schlüssel aktualisiert%2$s.</item>
</plurals>
<plurals name="import_keys_added">
- <item quantity="one">Schlüssel erfolgreich importiert%2$s.</item>
- <item quantity="other">%1$d Schlüssel erfolgreich importiert%2$s.</item>
+ <item quantity="one">Ein Schlüssel wurde erfolgreich importiert%2$s.</item>
+ <item quantity="other">%1$d Schlüssel wurden erfolgreich importiert%2$s.</item>
</plurals>
<plurals name="import_keys_updated">
- <item quantity="one">Schlüssel erfolgreich aktualisiert%2$s.</item>
- <item quantity="other">%1$d Schlüssel erfolgreich aktualisiert%2$s.</item>
+ <item quantity="one">Ein Schlüssel wurde erfolgreich aktualisiert%2$s.</item>
+ <item quantity="other">%1$d Schlüssel wurden erfolgreich aktualisiert%2$s.</item>
</plurals>
<plurals name="import_keys_with_errors">
<item quantity="one">Import eines Schlüssels fehlgeschlagen!</item>
<item quantity="other">Import von %d Schlüsseln fehlgeschlagen!</item>
</plurals>
<plurals name="import_error">
- <item quantity="one">Import fehlgeschlagen!</item>
+ <item quantity="one">Import eines Schlüssels fehlgeschlagen!</item>
<item quantity="other">Import von %d Schlüsseln fehlgeschlagen!</item>
</plurals>
<string name="import_error_nothing">Nichts zu importieren.</string>
- <string name="import_error_nothing_cancelled">Import abgebrochen.</string>
+ <string name="import_error_nothing_cancelled">Import wurde abgebrochen.</string>
<!--Delete result toast-->
<plurals name="delete_ok_but_fail_1">
- <item quantity="one">Schlüssel wurde erfolgreich gelöscht</item>
+ <item quantity="one">Ein Schlüssel wurde erfolgreich gelöscht</item>
<item quantity="other">%1$d Schlüssel wurden erfolgreich gelöscht</item>
</plurals>
<plurals name="delete_ok_but_fail_2">
@@ -476,7 +469,7 @@
<item quantity="other">, aber das Löschen von %1$d Schlüsseln ist fehlgeschlagen%2$s.</item>
</plurals>
<plurals name="delete_ok">
- <item quantity="one">Schlüssel wurde erfolgreich gelöscht%2$s.</item>
+ <item quantity="one">Ein Schlüssel wurde erfolgreich gelöscht%2$s.</item>
<item quantity="other">%1$d Schlüssel wurden erfolgreich gelöscht%2$s.</item>
</plurals>
<plurals name="delete_fail">
@@ -492,8 +485,8 @@
<string name="revoke_cancelled">Widerrufvorgang abgebrochen.</string>
<!--Certify result toast-->
<plurals name="certify_keys_ok">
- <item quantity="one">Schlüssel wurde erfolgreich beglaubigt%2$s.</item>
- <item quantity="other">%1$d Schlüssel wurden erfolgreich beglaubigt%2$s.</item>
+ <item quantity="one">Ein Schlüssel wurde erfolgreich bestätigt%2$s.</item>
+ <item quantity="other">%1$d Schlüssel wurden erfolgreich bestätigt%2$s.</item>
</plurals>
<plurals name="certify_keys_with_errors">
<item quantity="one">Beglaubigung fehlgeschlagen!</item>
@@ -505,7 +498,7 @@
</plurals>
<!--Intent labels-->
<string name="intent_decrypt_file">Datei entschlüsseln mit OpenKeychain</string>
- <string name="intent_import_key">Schlüssel importieren mit OpenKeychain</string>
+ <string name="intent_import_key">Schlüssel mit OpenKeychain importieren</string>
<string name="intent_send_encrypt">Verschlüsseln mit OpenKeychain </string>
<string name="intent_send_decrypt">Entschlüsseln mit OpenKeychain </string>
<!--Remote API-->
@@ -528,7 +521,7 @@
<string name="api_settings_advanced">Erweiterte Informationen</string>
<string name="api_settings_allowed_keys">Erlaubte Schlüssel</string>
<string name="api_settings_settings">Einstellungen</string>
- <string name="api_settings_key">Schlüssel des Kontos:</string>
+ <string name="api_settings_key">Schlüssel des Benutzerkontos:</string>
<string name="api_settings_accounts_empty">Keine Benutzerkonten mit dieser Anwendung verknüpft.</string>
<string name="api_create_account_text">Für dieses Benutzerkonto ist kein Schlüssel konfiguriert. Bitte wähle einen deiner existierenden Schlüssel aus oder erzeuge einen neuen.\nApps können nur hier ausgewählte Schlüssel nutzen!</string>
<string name="api_update_account_text">Der Schlüssel für dieses Benutzerkonto wurde gelöscht. Bitte wähle einen anderen aus!\nApps können nur hier ausgewählte Schlüssel nutzen.</string>
@@ -566,7 +559,10 @@
</plurals>
<string name="key_list_empty_text1">Keine Schlüssel gefunden!</string>
<string name="key_list_filter_show_all">Alle Schlüssel anzeigen</string>
- <string name="key_list_filter_show_certified">Nur beglaubigte Schlüssel anzeigen</string>
+ <string name="key_list_filter_show_certified">Nur bestätigte Schlüssel anzeigen</string>
+ <string name="key_list_fab_qr_code">QR-Code einscannen</string>
+ <string name="key_list_fab_search">Schlüsselsuche</string>
+ <string name="key_list_fab_import">Aus Datei importieren</string>
<!--Key view-->
<string name="key_view_action_edit">Schlüssel bearbeiten</string>
<string name="key_view_action_encrypt">Text verschlüsseln</string>
@@ -583,23 +579,16 @@
<string name="key_view_tab_keybase">Keybase.io</string>
<string name="user_id_info_revoked_title">Widerrufen</string>
<string name="user_id_info_revoked_text">Diese Identität wurde vom Schlüsselinhaber widerrufen. Sie ist nicht mehr gültig.</string>
- <string name="user_id_info_certified_title">Beglaubigt</string>
- <string name="user_id_info_certified_text">Diese Identität wurde von dir beglaubigt.</string>
- <string name="user_id_info_uncertified_title">Nicht beglaubigt</string>
- <string name="user_id_info_uncertified_text">Diese Identität wurde noch nicht beglaubigt. Du kannst nicht sicher sein, dass diese Identität wirklich zu einer bestimmten Person gehört.</string>
+ <string name="user_id_info_certified_title">Bestätigt</string>
+ <string name="user_id_info_certified_text">Diese Identität wurde von dir bestätigt.</string>
+ <string name="user_id_info_uncertified_title">Nicht bestätigt</string>
+ <string name="user_id_info_uncertified_text">Diese Identität wurde noch nicht bestätigt. Du kannst nicht sicher sein, dass diese Identität wirklich zu einer bestimmten Person gehört.</string>
<string name="user_id_info_invalid_title">Ungültig</string>
<string name="user_id_info_invalid_text">Etwas ist mit dieser Identität nicht in Ordnung!</string>
<!--Key trust-->
- <string name="key_trust_already_verified">Du hast diesen Schlüssel bereits bestätigt!</string>
- <string name="key_trust_it_is_yours">Dies ist einer deiner Schlüssel!</string>
- <string name="key_trust_maybe">Dieser Schlüssel ist weder widerrufen, noch abgelaufen.\nDu hast ihn bisher nicht bestätigt, kannst dich aber dazu entscheiden ihm zu vertrauen.</string>
- <string name="key_trust_revoked">Dieser Schlüssel wurde vom Schlüsselinhaber widerrufen. Du solltest ihm nicht vertrauen.</string>
- <string name="key_trust_expired">Dieser Schlüssel ist abgelaufen. Du solltest ihm nicht vertrauen.</string>
- <string name="key_trust_old_keys">Es ist möglicherweise in Ordnung dies zu nutzen, um eine alte Nachricht zu entschlüsseln, die aus der Zeit stammt, als der Schlüssel noch gültig war.</string>
- <string name="key_trust_no_cloud_evidence">Kein Nachweis aus der Cloud zur Vertrauenswürdigkeit dieses Schlüssels.</string>
+ <string name="key_trust_no_cloud_evidence">Es gibt keinen Nachweis aus dem Internet zur Vertrauenswürdigkeit dieses Schlüssels.</string>
<string name="key_trust_start_cloud_search">Suche beginnen</string>
<string name="key_trust_results_prefix">Keybase.io bietet \"Nachweise\" die bestätigen, dass der Schlüsselinhaber:</string>
- <string name="key_trust_header_text">Hinweis: Keybase.io-Nachweise sind ein experimentelles Feature von OpenKeychain. Wir rufen dazu auf, zusätzlich zur Bestätigung, QR-Codes zu nutzen oder Schlüssel via NFC auszutauschen.</string>
<!--keybase proof stuff-->
<string name="keybase_narrative_twitter">Auf Twitter schreibt, als %s</string>
<string name="keybase_narrative_github">Auf GitHub bekannt ist, als %s</string>
@@ -657,7 +646,7 @@
<string name="edit_key_error_bad_nfc_size">Die Schlüssellänge wird von dieser Smartcard nicht unterstützt!</string>
<string name="edit_key_error_bad_nfc_stripped">Schlüssel kann nicht auf Smartcard verschoben werden (entweder er ist gekürzt oder \'auf Karte umgeleitet\')!</string>
<!--Create key-->
- <string name="create_key_upload">Mit der Cloud synchronisieren</string>
+ <string name="create_key_upload">Mit dem Internet synchronisieren</string>
<string name="create_key_empty">Dieses Feld wird benötigt</string>
<string name="create_key_passphrases_not_equal">Passwörter stimmen nicht überein</string>
<string name="create_key_final_text">Du hast folgende Identität eingegeben:</string>
@@ -673,12 +662,9 @@
<string name="create_key_add_email_text">Es sind zusätzliche E-Mail-Adressen mit diesem Schlüssel verknüpft, die zur sicheren Kommunikation verwendet werden können.</string>
<string name="create_key_email_already_exists_text">E-Mail-Adresse wurde bereits hinzugefügt</string>
<string name="create_key_email_invalid_email">Format der E-Mail-Adresse ist ungültig</string>
- <string name="create_key_yubi_key_pin_text">Bitte die PIN gut merken, sie wird benötigt um später deinen YubiKey verwenden zu können. Schreibe zudem die Admin-PIN auf und hinterlege sie an einem sicheren Ort.</string>
<string name="create_key_yubi_key_pin">PIN</string>
<string name="create_key_yubi_key_admin_pin">Admin-PIN</string>
- <string name="create_key_yubi_key_pin_repeat_text">Zum Fortfahren bitte PIN und Admin-PIN eingeben.</string>
<string name="create_key_yubi_key_pin_repeat">PIN wiederholen</string>
- <string name="create_key_yubi_key_admin_pin_repeat">Admin-PIN wiederholen</string>
<string name="create_key_yubi_key_pin_not_correct">PIN ist nicht richtig!</string>
<!--View key-->
<string name="view_key_revoked">Widerrufen: Schlüssel darf nicht mehr genutzt werden!</string>
@@ -691,7 +677,6 @@
<!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Schlüsselserver hinzufügen</string>
<string name="edit_keyserver_dialog_title">Schlüsselserver bearbeiten</string>
- <string name="add_keyserver_verified">Schlüsselserver verifiziert!</string>
<string name="add_keyserver_without_verification">Schlüsselserver ohne Verifikation hinzugefügt.</string>
<string name="add_keyserver_invalid_url">Ungültige URL!</string>
<string name="add_keyserver_connection_failed">Verbindung zum Schlüsselserver fehlgeschlagen. Bitte überprüfe die URL und deine Internetverbindung.</string>
@@ -704,7 +689,6 @@
<string name="drawer_open">Menü öffnen</string>
<string name="drawer_close">Menü schließen</string>
<string name="my_keys">Meine Schlüssel</string>
- <string name="nav_backup">Backup</string>
<!--hints-->
<string name="encrypt_content_edit_text_hint">Text eingeben</string>
<!--certs-->
@@ -722,7 +706,7 @@
<string name="msg_cancelled">Vorgang abgebrochen.</string>
<!--Import Public log entries-->
<string name="msg_ip_apply_batch">Stapel-Einfügeoperationen werden angewendet.</string>
- <string name="msg_ip_bad_type_secret">Es wurde versucht einen privaten Schlüsselbund als öffentlichen zu importieren. Dies ist ein Fehler, bitte reiche einen Fehlerbericht ein!</string>
+ <string name="msg_ip_bad_type_secret">Es wurde versucht einen privaten Schlüsselbund als Öffentlichen zu importieren. Dies ist ein Fehler, bitte reiche einen Fehlerbericht ein!</string>
<string name="msg_ip_delete_old_fail">Kein alter Schlüssel gelöscht (Einen neuen erzeugen?)</string>
<string name="msg_ip_delete_old_ok">Alte Schlüssel aus der Datenbank löschen</string>
<string name="msg_ip_encode_fail">Vorgang aufgrund eines Kodierungsfehlers fehlgeschlagen</string>
@@ -731,11 +715,11 @@
<string name="msg_ip_error_remote_ex">Vorgang aufgrund eines internen Fehlers fehlgeschlagen</string>
<string name="msg_ip">Importiere öffentlichen Schlüsselbund %s</string>
<string name="msg_ip_insert_keyring">Schlüsselbunddaten werden kodiert</string>
- <string name="msg_ip_insert_keys">Analysiere Schlüssel</string>
+ <string name="msg_ip_insert_keys">Schlüssel werden analysiert</string>
<string name="msg_ip_prepare">Datenbankvorgänge werden vorbereitet</string>
<string name="msg_ip_master">Hauptschlüssel %s wird verarbeitet</string>
- <string name="msg_ip_master_expired">Schlüsselbund abgelaufen am %s</string>
- <string name="msg_ip_master_expires">Schlüsselbund läuft ab am %s</string>
+ <string name="msg_ip_master_expired">Schlüsselbund ist am %s abgelaufen</string>
+ <string name="msg_ip_master_expires">Schlüsselbund wird am %s ablaufen</string>
<string name="msg_ip_master_flags_unspecified">Haupt-Attribute: Unspezifiziert (alle angenommen)</string>
<string name="msg_ip_master_flags_cesa">Haupt-Attribute: beglaubigen, verschlüsseln, signieren und authentifizieren</string>
<string name="msg_ip_master_flags_cesx">Haupt-Attribute: beglaubigen, verschlüsseln und signieren</string>
@@ -755,9 +739,9 @@
<string name="msg_ip_master_flags_xxxx">Haupt-Attribute: keine</string>
<string name="msg_ip_merge_public">Importierte Daten werden in vorhandenen öffentlichen Schlüsselbund eingefügt</string>
<string name="msg_ip_merge_secret">Importierte Daten werden in vorhandenen privaten Schlüsselbund eingefügt</string>
- <string name="msg_ip_subkey">Verarbeite Unterschlüssel %s</string>
- <string name="msg_ip_subkey_expired">Unterschlüssel abgelaufen am %s</string>
- <string name="msg_ip_subkey_expires">Unterschlüssel läuft ab am %s</string>
+ <string name="msg_ip_subkey">Unterschlüssel %s werden verarbeitet</string>
+ <string name="msg_ip_subkey_expired">Unterschlüssel ist am %s abgelaufen</string>
+ <string name="msg_ip_subkey_expires">Unterschlüssel wird am %s ablaufen</string>
<string name="msg_ip_subkey_flags_unspecified">Unterschlüssel-Attribute: Unspezifiziert (alle angenommen)</string>
<string name="msg_ip_subkey_flags_cesa">Unterschlüssel-Attribute: beglaubigen, verschlüsseln, signieren und authentifizieren</string>
<string name="msg_ip_subkey_flags_cesx">Unterschlüssel-Attribute: beglaubigen, verschlüsseln und signieren</string>
@@ -777,7 +761,7 @@
<string name="msg_ip_subkey_flags_xxxx">Unterschlüssel-Attribute: keine</string>
<string name="msg_ip_success">Öffentlicher Schlüsselbund erfolgreich importiert</string>
<string name="msg_ip_success_identical">Schlüsselbund enthält keine neuen Daten, es gibt nichts zu tun</string>
- <string name="msg_ip_reinsert_secret">Privaten Schlüssel wiedereinfügen</string>
+ <string name="msg_ip_reinsert_secret">Privater Schlüssel wird wiedereingefügt</string>
<string name="msg_ip_uid_cert_bad">Fehlerhafte Beglaubigung gefunden!</string>
<string name="msg_ip_uid_cert_error">Fehler beim Verarbeiten der Beglaubigung!</string>
<string name="msg_ip_uid_cert_nonrevoke">Besitzt bereits eine nicht widerrufbare Beglaubigung, wird übersprungen.</string>
@@ -812,7 +796,7 @@
</plurals>
<string name="msg_ip_uat_classifying">Klassifiziere Benutzerattribute</string>
<string name="msg_ip_uat_revoked">Benutzerattribut wurde widerrufen</string>
- <string name="msg_is_bad_type_public">Es wurde versucht einen öffentlichen Schlüsselbund als privaten zu importieren. Dies ist ein Fehler, bitte reiche einen Fehlerbericht ein!</string>
+ <string name="msg_is_bad_type_public">Es wurde versucht einen öffentlichen Schlüsselbund als Privaten zu importieren. Dies ist ein Fehler, bitte reiche einen Fehlerbericht ein!</string>
<string name="msg_is_bad_type_uncanon">Es wurde versucht, einen Schlüsselbund ohne vorschriftsmäßiges Format zu importieren. Dies ist ein Fehler, bitte reiche einen Fehlerbericht ein!</string>
<!--Import Secret log entries-->
<string name="msg_is">Importiere privaten Schlüssel %s</string>
@@ -922,7 +906,6 @@
<string name="msg_cr_error_no_user_id">Schlüsselbünde müssen mindestens eine User-ID enthalten!</string>
<string name="msg_cr_error_no_certify">Hauptschlüssel benötigt das Attribut beglaubigen!</string>
<string name="msg_cr_error_null_expiry">Ablaufdatum kann bei Schlüsselerstellung nicht \'gleiche wie vorher\' sein. Dies ist ein Programmierfehler, bitte reiche einen Fehlerbericht ein!</string>
- <string name="msg_cr_error_keysize_512">Schlüssellänge muss größer/gleich 512 sein!</string>
<string name="msg_cr_error_no_curve">Keine Schlüssellänge spezifiziert! Dies ist ein Progammierfehler, bitte reiche einen Fehlerbericht ein!</string>
<string name="msg_cr_error_no_keysize">Keine Elliptische Kurve spezifiziert! Dies ist ein Progammierfehler, bitte reiche einen Fehlerbericht ein!</string>
<string name="msg_cr_error_internal_pgp">Interner OpenPGP Fehler!</string>
@@ -946,7 +929,7 @@
<string name="msg_mf_error_restricted">Versuch einen eingeschränkten Vorgang ohne Passwort auszuführen! Dies ist ein Programmierfehler, bitte reiche einen Fehlerbericht ein!</string>
<string name="msg_mf_error_revoked_primary">Widerrufene User-IDs können nicht primäre IDs sein!</string>
<string name="msg_mf_error_null_expiry">Ablaufdatum kann bei Unterschlüsselerstellung nicht \"identisch wie vorher\" sein. Dies ist ein Programmierfehler, bitte reiche einen Fehlerbericht ein!</string>
- <string name="msg_mf_error_noop">Nichts zu machen!</string>
+ <string name="msg_mf_error_noop">Nichts zu tun!</string>
<string name="msg_mf_error_passphrase_master">Schwerer Fehler beim Entschlüsseln des Hauptschlüssels! Dies ist wahrscheinlich ein Programmierfehler, bitte reiche einen Fehlerbericht ein!</string>
<string name="msg_mf_error_pgp">Interner OpenPGP Fehler!</string>
<string name="msg_mf_error_sig">Signaturfehler!</string>
@@ -973,14 +956,14 @@
<string name="msg_mf_subkey_new">Füge neuen Unterschlüssel vom Typ %s hinzu</string>
<string name="msg_mf_subkey_new_id">Neue Unterschlüsselkennung: %s</string>
<string name="msg_mf_error_past_expiry">Ablaufdatum kann nicht in der Vergangenheit liegen!</string>
- <string name="msg_mf_subkey_revoke">Widerrufe Unterschlüssel %s</string>
+ <string name="msg_mf_subkey_revoke">Unterschlüssel %s wird widerrufen</string>
<string name="msg_mf_subkey_strip">Kürze Unterschlüssel %s</string>
<string name="msg_mf_keytocard_start">Verschiebe Unterschlüssel %s auf Smartcard</string>
<string name="msg_mf_keytocard_finish">%1$s auf Smartcard %2$s verschoben</string>
<string name="msg_mf_success">Schlüsselbund erfolgreich verändert</string>
<string name="msg_mf_uid_add">User-ID %s wird hinzugefügt</string>
<string name="msg_mf_uid_primary">Primäre User-ID wird geändert in %s</string>
- <string name="msg_mf_uid_revoke">Widerrufe User-ID %s</string>
+ <string name="msg_mf_uid_revoke">User-ID %s wird widerrufen</string>
<string name="msg_mf_uid_error_empty">User-ID darf nicht leer sein!</string>
<string name="msg_mf_uat_error_empty">Benutzerattribut darf nicht leer sein!</string>
<string name="msg_mf_uat_add_image">Bild-Benutzerattribut wird hinzugefügt</string>
@@ -1008,13 +991,13 @@
<string name="msg_con_recursive">Rekursive Zusammenführung wird übersprungen</string>
<string name="msg_con_recover_unknown">Zusammenführungsvorgang aus unbekanntem Zustand wird fortgesetzt</string>
<plurals name="msg_con_reimport_public">
- <item quantity="one">Reimportiere einen öffentlichen Schlüssel</item>
- <item quantity="other">Reimportiere %d öffentliche Schlüssel</item>
+ <item quantity="one">Ein öffentlicher Schlüssel wird reimportiert</item>
+ <item quantity="other">%d öffentliche Schlüssel werden reimportiert</item>
</plurals>
<string name="msg_con_reimport_public_skip">Keine öffentlichen Schlüssel für Reimport, überspringe...</string>
<plurals name="msg_con_reimport_secret">
- <item quantity="one">Reimportiere einen privaten Schlüssel</item>
- <item quantity="other">Reimportiere %d private Schlüssel</item>
+ <item quantity="one">Ein privater Schlüssel wird reimportiert</item>
+ <item quantity="other">%d private Schlüssel werden reimportiert</item>
</plurals>
<string name="msg_con_reimport_secret_skip">Keine privaten Schlüssel für Reimport, überspringe...</string>
<string name="msg_con_warn_delete_public">Ausnahmefehler beim Löschen der öffentlichen Zwischenspeicherdatei</string>
@@ -1042,7 +1025,7 @@
<string name="msg_dc_askip_no_key">Daten mit unbekanntem Schlüssel verschlüsselt, überspringe...</string>
<string name="msg_dc_askip_not_allowed">Daten mit nicht zugelassenem Schlüssel verschlüsselt, überspringe...</string>
<string name="msg_dc_asym">Block asymmetrisch verschlüsselter Daten für Schlüssel %s gefunden</string>
- <string name="msg_dc_charset">Zeichensatz-Header gefunden: \'%s\'</string>
+ <string name="msg_dc_charset">Ein Zeichensatz-Header wurde gefunden: \'%s\'</string>
<string name="msg_dc_clear_data">Verarbeite Klartextdaten</string>
<string name="msg_dc_clear_decompress">Entpacke komprimierte Daten</string>
<string name="msg_dc_clear_meta_file">Dateiname: %s</string>
@@ -1050,9 +1033,9 @@
<string name="msg_dc_clear_meta_size">Dateigröße: %s</string>
<string name="msg_dc_clear_meta_size_unknown">Dateigröße unbekannt</string>
<string name="msg_dc_clear_meta_time">Änderungszeit: %s</string>
- <string name="msg_dc_clear_signature_bad">Signaturprüfung NICHT OK!</string>
+ <string name="msg_dc_clear_signature_bad">Signaturprüfung NICHT in Ordnung!</string>
<string name="msg_dc_clear_signature_check">Signaturdaten werden verifiziert</string>
- <string name="msg_dc_clear_signature_ok">Signaturprüfung OK</string>
+ <string name="msg_dc_clear_signature_ok">Signaturprüfung in Ordnung</string>
<string name="msg_dc_clear_signature">Speichere Signatur für später</string>
<string name="msg_dc_clear">Verarbeite Klartextdaten</string>
<string name="msg_dc_error_bad_passphrase">Fehler beim Entsperren des Schlüssels, falsches Passwort!</string>
@@ -1066,11 +1049,11 @@
<string name="msg_dc_error_no_data">Keine verschlüsselten Daten im Datenstrom gefunden!</string>
<string name="msg_dc_error_no_key">Keine verschlüsselten Daten mit bekanntem privatem Schlüssel im Datenstrom gefunden!</string>
<string name="msg_dc_error_pgp_exception">Während eines Vorgangs ist ein OpenPGP-Ausnahmefehler aufgetreten!</string>
- <string name="msg_dc_integrity_check_ok">Integritätsprüfung OK!</string>
+ <string name="msg_dc_integrity_check_ok">Integritätsprüfung in Ordnung!</string>
<string name="msg_dc_ok_meta_only">Es wurden nur Metadaten angefragt, überspringe Entschlüsselung</string>
<string name="msg_dc_ok">Entschlüsselung/Verifikation abgeschlossen</string>
<string name="msg_dc_pass_cached">Passwort aus Zwischenspeicher verwenden</string>
- <string name="msg_dc_pending_nfc">NFC-Token benötigt, Benutzereingabe wird angefordert…</string>
+ <string name="msg_dc_pending_nfc">NFC-Token wird benötigt, Benutzereingabe wird angefordert…</string>
<string name="msg_dc_pending_passphrase">Passwort erforderlich, Benutzereingabe wird angefordert…</string>
<string name="msg_dc_prep_streams">Bereite Datenströme zur Entschlüsselung vor</string>
<string name="msg_dc">Starte Entschlüsselungsvorgang...</string>
@@ -1086,8 +1069,6 @@
<string name="msg_dc_insecure_key">Unsicherer Schlüssel: Entweder ist die Bitlänge von RSA/DSA/ElGamal zu kurz oder die ECC-Kurve bzw. der ECC-Algorithmus wird als unsicher angesehen! Das kann vorkommen wenn die Anwendung veraltet ist, oder durch einen Angriff.</string>
<!--Messages for VerifySignedLiteralData operation-->
<string name="msg_vl">Starte Signaturprüfung</string>
- <string name="msg_vl_error_no_siglist">Keine Signaturliste in signierten Literaldaten</string>
- <string name="msg_vl_error_wrong_key">Nachricht nicht mit dem richtigen Schlüssel signiert</string>
<string name="msg_vl_error_missing_literal">Keine Nutzdaten in signierten Literaldaten</string>
<string name="msg_vl_clear_meta_file">Dateiname: %s</string>
<string name="msg_vl_clear_meta_mime">MIME-Typ: %s</string>
@@ -1098,16 +1079,15 @@
<string name="msg_vl_ok">OK</string>
<!--Messages for SignEncrypt operation-->
<string name="msg_se">Starte Signier-/Verschlüsselungsvorgang</string>
- <string name="msg_se_input_bytes">Verarbeite Eingabe aus Bytearray</string>
- <string name="msg_se_input_uri">Verarbeite Eingabe aus URI</string>
+ <string name="msg_se_input_bytes">Eingabe aus Bytearray wird verarbeitet</string>
+ <string name="msg_se_input_uri">Eingabe aus URI wird verarbeitet</string>
<string name="msg_se_error_no_input">Keine Eingabe vorhanden!</string>
- <string name="msg_se_error_input_uri_not_found">Fehler beim Öffnen des URI zum Lesen!</string>
- <string name="msg_se_error_output_uri_not_found">Fehler beim Öffnen des URI zum Schreiben!</string>
+ <string name="msg_se_error_input_uri_not_found">Fehler beim Öffnen der URI zum Lesen!</string>
+ <string name="msg_se_error_output_uri_not_found">Fehler beim Öffnen der URI zum Schreiben!</string>
<string name="msg_se_error_too_many_inputs">Mehr Eingaben als Ausgaben spezifiziert! Dies ist vermutlich ein Programmierfehler, diesen bitte melden!</string>
<string name="msg_se_success">Signier-/Verschlüsselungsvorgang erfolgreich</string>
<!--Messages for PgpSignEncrypt operation-->
<string name="msg_pse_asymmetric">Bereite öffentliche Schlüssel für Verschlüsselung vor</string>
- <string name="msg_pse_clearsign_only">Signieren von Klartexteingaben wird nicht unterstützt!</string>
<string name="msg_pse_compressing">Bereite Kompression vor</string>
<string name="msg_pse_encrypting">Daten werden verschlüsselt</string>
<string name="msg_pse_error_bad_passphrase">Falsches Passwort!</string>
@@ -1123,7 +1103,7 @@
<string name="msg_pse_key_unknown">Fehlender Schlüssel für Verschlüsselung: %s</string>
<string name="msg_pse_key_warn">Fehlerhafter Schlüssel für Verschlüsselung: %s</string>
<string name="msg_pse_ok">Signierungs-/Verschlüsselungsvorgang erfolgreich!</string>
- <string name="msg_pse_pending_nfc">NFC-Token benötigt, Benutzereingabe wird angefordert…</string>
+ <string name="msg_pse_pending_nfc">NFC-Token wird benötigt, Benutzereingabe wird angefordert…</string>
<string name="msg_pse_pending_passphrase">Passwort erforderlich, Benutzereingabe wird angefordert…</string>
<string name="msg_pse_signing">Signiere Daten (ohne Verschlüsselung)</string>
<string name="msg_pse_signing_cleartext">Erstelle Klartextsignatur</string>
@@ -1133,8 +1113,8 @@
<string name="msg_pse_symmetric">Bereite symmetrische Verschlüsselung vor</string>
<string name="msg_crt_certifying">Beglaubigungen werden erzeugt</string>
<plurals name="msg_crt_certify_uids">
- <item quantity="one">Beglaubige eine User-ID für Schlüssel %2$s</item>
- <item quantity="other">Beglaubige %1$d User-IDs für Schlüssel %2$s</item>
+ <item quantity="one">Eine User-ID von Schlüssel %2$s wird beglaubigt</item>
+ <item quantity="other">%1$d User-IDs von Schlüssel %2$s werden beglaubigt</item>
</plurals>
<plurals name="msg_crt_certify_uats">
<item quantity="one">Beglaubige ein Benutzerattribut für Schlüssel %2$s</item>
@@ -1157,44 +1137,21 @@
<string name="msg_crt_warn_upload_failed">Hochladevorgang fehlgeschlagen!</string>
<string name="msg_crt_upload_success">Schlüssel wurde erfolgreich hochgeladen</string>
<plurals name="msg_import">
- <item quantity="one">Schlüssel wird importiert</item>
+ <item quantity="one">Ein Schlüssel wird importiert</item>
<item quantity="other">%d Schlüssel werden importiert</item>
</plurals>
<string name="msg_import_fetch_error_decode">Fehler beim Dekodieren des abgerufenen Schlüsselbundes!</string>
<string name="msg_import_fetch_error">Schlüssel konnte nicht abgerufen werden! (Netzwerkprobleme?)</string>
- <string name="msg_import_fetch_keybase">Empfange von keybase.io: %s</string>
- <string name="msg_import_fetch_error_keyserver">Konnte Schlüssel nicht vom Schlüsselserver abrufen: %s</string>
+ <string name="msg_import_fetch_keybase">Von Keybase.io wird abgerufen: %s</string>
<string name="msg_import_fetch_keyserver">Empfange von Schlüsselserver: %s</string>
<string name="msg_import_fetch_keyserver_ok">Schlüssel erfolgreich heruntergeladen</string>
<string name="msg_import_keyserver">Verwende Schlüsselserver %s</string>
- <string name="msg_import_fingerprint_error">Fingerabdruck des abgerufenen Schlüssels entspricht nicht dem Erwarteten!</string>
- <string name="msg_import_fingerprint_ok">Fingerabdrucktest in Ordnung</string>
<string name="msg_import_merge">Abgerufene Daten werden eingefügt</string>
<string name="msg_import_merge_error">Fehler beim Zusammenführen der abgerufenen Daten!</string>
<string name="msg_import_error">Importvorgang fehlgeschlagen!</string>
<string name="msg_import_error_io">Importvorgang ist aufgrund eines Ein-/Ausgabefehlers fehlgeschlagen!</string>
<string name="msg_import_partial">Importvorgang erfolgreich, mit Fehlern!</string>
<string name="msg_import_success">Importvorgang erfolgreich!</string>
- <plurals name="msg_export">
- <item quantity="one">Schlüssel wird exportiert</item>
- <item quantity="other">%d Schlüssel werden exportiert</item>
- </plurals>
- <string name="msg_export_file_name">Dateiname: %s</string>
- <string name="msg_export_all">Exportiere alle Schlüssel</string>
- <string name="msg_export_public">Exportiere öffentlichen Schlüssel %s</string>
- <string name="msg_export_upload_public">Öffentlicher Schlüssel %s wird hochgeladen</string>
- <string name="msg_export_secret">Exportiere privaten Schlüssel %s</string>
- <string name="msg_export_error_no_file">Kein Dateiname spezifiziert!</string>
- <string name="msg_export_error_fopen">Fehler beim Öffnen der Datei !</string>
- <string name="msg_export_error_no_uri">Keine URI spezifiziert!</string>
- <string name="msg_export_error_uri_open">Fehler beim Öffnen des URI-Streams!</string>
- <string name="msg_export_error_storage">Speicher ist nicht Schreibbereit !</string>
- <string name="msg_export_error_db">Datenbankfehler!</string>
- <string name="msg_export_error_io">Eingabe/Ausgabe Fehler!</string>
- <string name="msg_export_error_key">Fehlber bei der Vorverarbeitung der Schlüsseldaten!</string>
- <string name="msg_export_error_upload">Fehler beim Hochladen des Schlüssels zum Server! Bitte überprüfe deine Internetverbindung</string>
- <string name="msg_export_success">Exportvorgang erfolgreich!</string>
- <string name="msg_export_upload_success">Hochladen auf Schlüsselserver erfolgreich</string>
<string name="msg_del_error_empty">Nichts zu löschen!</string>
<string name="msg_del_error_multi_secret">Private Schlüssel können nur einzeln gelöscht werden!</string>
<plurals name="msg_del">
@@ -1213,10 +1170,29 @@
<item quantity="other">Fehler beim Löschen von %d Schlüsseln</item>
</plurals>
<string name="msg_revoke_error_empty">Nichts zu widerrufen!</string>
- <string name="msg_revoke_error_not_found">Schlüssel zum Widerrufen nicht gefunden!</string>
- <string name="msg_revoke_key">Widerrufe Schlüssel %s</string>
+ <string name="msg_revoke_error_not_found">Schlüssel zum Widerrufen wurde nicht gefunden!</string>
+ <string name="msg_revoke_key">Schlüssel %s wird widerrufen</string>
<string name="msg_revoke_key_fail">Fehler beim Widerrufen des Schlüssels</string>
<string name="msg_revoke_ok">Schlüssel erfolgreich widerrufen</string>
+ <!--Linked Identity verification-->
+ <string name="msg_lv">Verknüpfte-Identität wird verifiziert…</string>
+ <string name="msg_lv_match">Nach Token wird gesucht</string>
+ <string name="msg_lv_match_error">Es wurde kein Token in der Ressource gefunden!</string>
+ <string name="msg_lv_fp_ok">Fingerabdruck in Ordnung.</string>
+ <string name="msg_lv_fp_error">Fingerabdrücke stimmen nicht überein!</string>
+ <string name="msg_lv_error_twitter_auth">Fehler beim Erhalten des Twitter-Authentifizierungs-Tokens!</string>
+ <string name="msg_lv_error_twitter_handle">Falsche Handle-Zuordnung des Twitter-Benutzerkontos in der Antwort!</string>
+ <string name="msg_lv_error_twitter_response">Unerwartete Antwort der Twitter-API!</string>
+ <string name="msg_lv_error_github_handle">Falsche Handle-Zuordnung des GitHub-Benutzerkontos in der Antwort!</string>
+ <string name="msg_lv_error_github_not_found">Gist enthält keine übereinstimmenden Dateien!</string>
+ <string name="msg_lv_fetch">URI \'%s\' wird abgerufen</string>
+ <string name="msg_lv_fetch_redir">Weiterleitung auf \'%s\' wird gefolgt</string>
+ <string name="msg_lv_fetch_ok">Erfolgreich abgerufen (HTTP %s)</string>
+ <string name="msg_lv_fetch_error">Serverfehler (HTTP %s)</string>
+ <string name="msg_lv_fetch_error_url">URL ist fehlerhaft!</string>
+ <string name="msg_lv_fetch_error_io">Ein-/Ausgabefehler!</string>
+ <string name="msg_lv_fetch_error_format">Formatfehler!</string>
+ <string name="msg_lv_fetch_error_nothing">Ressource wurde nicht gefunden!</string>
<string name="msg_acc_saved">Benutzerkonto gespeichert</string>
<string name="msg_download_success">Erfolgreich heruntergeladen!</string>
<string name="msg_download_no_valid_keys">Keine gültigen Schlüssel in der Datei/Zwischenablage gefunden!</string>
@@ -1230,21 +1206,16 @@
<string name="msg_download_query_too_short_or_too_many_responses">Entweder keine oder zu viele Schlüssel wurden gefunden, bitte die Suchanfrage prä­zi­sie­ren!</string>
<string name="msg_download_query_failed">Beim Suchen der Schlüssel ist ein Fehler aufgetreten.</string>
<!--Messages for Keybase Verification operation-->
- <string name="msg_keybase_verification">Versuche Keybase-Verifikation für %s</string>
+ <string name="msg_keybase_verification">Versuche Keybase.io-Verifikation für %s</string>
<string name="msg_keybase_error_no_prover">Kein Nachweis-Prüfer gefunden für %s</string>
<string name="msg_keybase_error_fetching_evidence">Problem beim Holen des Nachweises</string>
- <string name="msg_keybase_error_key_mismatch">Schlüssel-Fingerabdruck stimmt nicht mit dem Fingerabdruck im Nachweis überein</string>
+ <string name="msg_keybase_error_key_mismatch">Fingerabdruck des Schlüssels stimmt nicht mit dem Fingerabdruck im Nachweis überein</string>
<string name="msg_keybase_error_dns_fail">Abfrage des DNS-TXT-Eintrags fehlgeschlagen</string>
<string name="msg_keybase_error_specific">%s</string>
<string name="msg_keybase_error_msg_payload_mismatch">Entschlüsselter Nachweis entspricht nicht dem erwarteten Wert</string>
- <!--Messages for Export Log operation-->
- <string name="msg_export_log_start">Exportiere Protokoll</string>
- <string name="msg_export_log_error_fopen">Fehler beim Öffnen der Datei</string>
- <string name="msg_export_log_error_no_file">Kein Dateiname spezifiziert!</string>
- <string name="msg_export_log_error_writing">Ein-/Ausgabefehler beim Schreiben in die Datei!</string>
- <string name="msg_export_log_success">Protokoll erfolgreich exportiert!</string>
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
- <string name="passp_cache_notif_click_to_clear">Passwörter löschen</string>
+ <string name="passp_cache_notif_click_to_clear">Berühren, um Passwörter zu vergessen</string>
<plurals name="passp_cache_notif_n_keys">
<item quantity="one">%d Passwort gemerkt</item>
<item quantity="other">%d Passwörter gemerkt</item>
@@ -1253,7 +1224,7 @@
<string name="passp_cache_notif_clear">Passwörter vergessen</string>
<string name="passp_cache_notif_pwd">Passwort</string>
<!--Keyserver sync-->
- <string name="keyserver_sync_orbot_notif_title">Synchronisierung aus der Cloud erfordert Orbot</string>
+ <string name="keyserver_sync_orbot_notif_title">Synchronisierung von Servern erfordert Orbot</string>
<string name="keyserver_sync_orbot_notif_msg">Zum Starten von Orbot tippen</string>
<string name="keyserver_sync_orbot_notif_start">Orbot starten</string>
<string name="keyserver_sync_orbot_notif_ignore">Direkt</string>
@@ -1273,18 +1244,16 @@
<string name="section_certifier_id">Beglaubiger</string>
<string name="section_cert">Beglaubigungsdetails</string>
<string name="label_user_id">Identität</string>
- <string name="unknown_uid">&lt;unbekannt&gt;</string>
+ <string name="unknown_uid"><![CDATA[<unbekannt>]]></string>
<string name="empty_certs">Keine Beglaubigungen für diesen Schlüssel</string>
<string name="certs_text">Nur geprüfte Eigenbeglaubigungen und geprüfte Beglaubigungen, die mit deinen Schlüsseln erzeugt wurden, werden hier angezeigt.</string>
<string name="section_uids_to_certify">Identitäten für</string>
<string name="certify_text">Die zu importierenden Schlüssel enthalten \"Identitäten\": Namen und E-Mail-Adressen. Wähle genau diejenigen zum Bestätigen aus, die deinen Erwartungen entsprechen.</string>
- <string name="certify_fingerprint_text">Vergleiche den angezeigten Fingerabdruck zeichenweise mit dem, der auf dem Gerät deines Gegenübers angezeigt wird.</string>
- <string name="certify_fingerprint_text2">Stimmen die angezeigten Fingerabdrücke überein?</string>
<string name="label_revocation">Widerrufsgrund</string>
<string name="label_cert_type">Typ</string>
<string name="error_key_not_found">Schlüssel nicht gefunden!</string>
<string name="error_key_processing">Fehler bei der Verarbeitung des Schlüssels!</string>
- <string name="key_stripped">nicht verfügbar</string>
+ <string name="key_stripped">gekürzt</string>
<string name="key_divert">auf Smartcard umleiten</string>
<string name="key_no_passphrase">kein Passwort</string>
<string name="key_unavailable">nicht verfügbar</string>
@@ -1303,9 +1272,9 @@
<string name="key_colon">Schlüssel:</string>
<string name="exchange_description">Um einen Schlüsselaustausch zu starten wähle auf der rechten Seite die Teilnehmer aus, drücke dann den \"Austausch starten\"-Knopf.\n\nDu wirst zusätzlich zwei Fragen gestellt bekommen um sicherzustellen, dass nur die richtigen Teilnehmer am Austausch beteiligt sind und deren Fingerabdrücke korrekt sind.</string>
<string name="btn_start_exchange">Austausch starten</string>
- <string name="user_id_none"><![CDATA[<kein>]]></string>
+ <string name="user_id_none"><![CDATA[<keine>]]></string>
<!--Android Account-->
- <string name="account_no_manual_account_creation">OpenKeychain-Benutzerkonten können nicht manuell angelegt werden.</string>
+ <string name="account_no_manual_account_creation">OpenKeychain-Benutzerkonten können nicht manuell erzeugt werden.</string>
<string name="account_privacy_title">Datenschutz</string>
<string name="account_privacy_text">OpenKeychain synchronisiert deine Kontakte nicht mit dem Internet. Es verknüpft lediglich Kontakte mit Schlüsseln auf der Basis von Namen und E-Mail-Adressen. Das alles findet offline auf deinem Gerät statt.</string>
<!--Passphrase wizard-->
@@ -1334,12 +1303,12 @@
<string name="nfc_write_succesful">Erfolgreich auf den NFC-Tag geschrieben</string>
<string name="unlocked">Entsperrt</string>
<string name="nfc_settings">Einstellungen</string>
- <string name="snack_yubikey_view">Ansicht</string>
+ <string name="snack_yubikey_view">Anzeigen</string>
<string name="snack_yubikey_import">Import</string>
<string name="button_bind_key">Schlüssel verbinden</string>
<string name="yubikey_serno">Seriennummer: %s</string>
<string name="yubikey_key_holder">Schlüsselinhaber:</string>
- <string name="yubikey_key_holder_not_set">Schlüsselnhaber: &lt;nicht gesetzt&gt;</string>
+ <string name="yubikey_key_holder_not_set"><![CDATA[Schlüsselinhaber: <nicht festgelegt>]]></string>
<string name="yubikey_status_bound">YubiKey stimmt überein und ist mit dem Schlüssel gekoppelt</string>
<string name="yubikey_status_unbound">YubiKey stimmt überein und kann mit dem Schlüssel gekoppelt werden</string>
<string name="yubikey_status_partly">YubiKey stimmt überein und ist teilweise mit dem Schlüssel gekoppelt</string>
@@ -1363,7 +1332,6 @@
<string name="error_nfc_header">YubiKey meldete ungültige %s Byte.</string>
<string name="error_nfc_tag_lost">YubiKey wurde zu früh abgenommen. Halte den YubiKey an die Rückseite, bis der Vorgang beendet ist.</string>
<string name="error_nfc_try_again">Erneut versuchen</string>
- <string name="error_pin_nodefault">Standard-PIN abgelehnt</string>
<string name="error_temp_file">Erstellen der temporären Datei fehlgeschlagen.</string>
<string name="btn_delete_original">Originaldatei löschen</string>
<string name="snack_encrypt_filenames_on">Dateinamen <b>sind</b> verschlüsselt.</string>
@@ -1375,10 +1343,10 @@
<string name="error_loading_keys">Fehler beim Laden der Schlüssel!</string>
<string name="error_empty_log">(Fehler, Protokoll leer)</string>
<string name="error_reading_text">Konnte Eingabe zur Entschlüsselung nicht lesen!</string>
- <string name="filename_unknown">&lt;kein Dateiname&gt;</string>
- <string name="filename_unknown_text">&lt;Klartextdaten&gt;</string>
+ <string name="filename_unknown">Unbekannter Dateiname (zum Öffnen klicken)</string>
+ <string name="filename_unknown_text">Text (zum Anzeigen klicken)</string>
<string name="intent_show">Signierten/verschlüsselten Inhalt anzeigen</string>
- <string name="view_internal">In OpenKeychain ansehen</string>
+ <string name="view_internal">In OpenKeychain anzeigen</string>
<string name="error_preparing_data">Fehler beim Vorbereiten der Daten!</string>
<string name="label_clip_title">Verschlüsselte Daten</string>
<string name="progress_processing">Wird verarbeitet...</string>
@@ -1392,4 +1360,59 @@
<string name="error_scan_fp">Fehler beim Scannen des Fingerabdrucks!</string>
<string name="error_scan_match">Fingerabdrücke stimmten nicht überein!</string>
<string name="error_expiry_past">Ablaufdatum liegt in der Vergangenheit!</string>
+ <string name="linked_create_https_1_1">Durch das Erzeugen einer Verknüpften-Identität dieses Typs kannst du deinen Schlüssel mit einer Webseite verknüpfen, die du kontrollierst.</string>
+ <string name="linked_create_https_1_2">Um das zu tun musst du eine Textdatei auf dieser Webseite veröffentlichen und dann eine Verknüpfte-Identität erzeugen, die auf diese Datei verlinkt.</string>
+ <string name="linked_create_https_1_3">Bitte gib eine URL ein bei der du eine Textdatei als Nachweis hinterlegen kannst. Beachte das dein Server HTTPS unterstützen muss und ein gültiges TLS Zertifikat benötigt!</string>
+ <string name="linked_create_https_1_4">Beispiel: https://example.com/pgpkey.txt</string>
+ <string name="linked_create_https_created">Die Nachweisdatei wurde erzeugt. Im nächsten Schritt solltest du sie speichern und zum URI hochladen, den du angegeben hast:</string>
+ <string name="linked_create_https_2_1">Eine Nachweisdatei für diesen URI wurde erzeugt:</string>
+ <string name="linked_create_https_2_2">Im nächsten Schritt solltest du Speichern und diese Datei hochladen.</string>
+ <string name="linked_create_https_2_3">Stelle sicher dass die Datei unter der korrekten URI erreichbar ist, prüfe danach deine Einstellungen.</string>
+ <string name="linked_create_https_2_4">Drücke nach erfolgreicher Verifikation auf Abschließen, um die Verknüpfte-Identität deinem Schlüsselbund hinzuzufügen und den Vorgang zu beenden.</string>
+ <string name="linked_create_twitter_1_1">Durch das Erzeugen einer verknüpften Identität dieses Typs kannst du deinen Schlüssel mit einem Twitter-Konto verknüpfen, das du kontrollierst.</string>
+ <string name="linked_create_twitter_1_2">Um das zu tun erstellst du einen bestimmten Tweet in deiner Chronik, anschließend erzeugst du eine Verknüpfte-Identität, die auf diesen Tweet verweist.</string>
+ <string name="linked_create_twitter_1_3">Zum Fortfahren gib bitte deinen Twitter-Namen an.</string>
+ <string name="linked_create_twitter_handle">Twitter-Handle</string>
+ <string name="linked_create_twitter_2_1">Drücke einen der Knöpfe um den Tweet abzusenden!</string>
+ <string name="linked_create_twitter_2_2">Du kannst den Tweet vor dem Absenden ändern solange der Text in den Klammern nicht geändert wird.</string>
+ <string name="linked_create_twitter_2_3">Sobald dein Tweet als &lt;b&gt;@%s&lt;/b&gt; veröffentlich wurde klicke die Verifizieren Schaltfläche um deine Chronik danach zu durchsuchen.</string>
+ <string name="linked_create_twitter_2_4">Drücke nach erfolgreicher Verifikation auf Abschließen, um die Verknüpfte-Identität deinem Schlüsselbund hinzuzufügen und den Vorgang zu beenden.</string>
+ <string name="linked_create_verify">Verifizieren</string>
+ <string name="linked_text_clipboard">Text wurde in die Zwischenablage kopiert</string>
+ <string name="linked_verified_https">Die Verknüpfung zwischen dieser Webseite und dem Schlüssel wurde sicher verifiziert. <b>Wenn du glaubst das die Webseite authentisch ist</b>, bestätige die Verifizierung mit deinem Schlüssel.</string>
+ <string name="linked_verified_github">Die Verknüpfung zwischen diesem GitHub-Konto und dem Schlüssel wurde sicher verifiziert. <b>Wenn du glaubst das dieses Konto authentisch ist</b>, bestätige die Verifizierung mit deinem Schlüssel.</string>
+ <string name="linked_verified_dns">Die Verknüpfung zwischen dieser Domain und dem Schlüssel wurde sicher verifiziert. <b>Wenn du glaubst das die Domain authentisch ist</b>, bestätige die Verifizierung mit deinem Schlüssel.</string>
+ <string name="linked_verified_twitter">Die Verknüpfung zwischen diesem Twitter-Konto und dem Schlüssel wurde sicher verifiziert. <b>Wenn du glaubst das dieses Konto authentisch ist</b>, bestätige die Verifizierung mit deinem Schlüssel.</string>
+ <string name="linked_verified_secret_https">Es ist alles in Ordnung.</string>
+ <string name="linked_verified_secret_github">Es ist alles in Ordnung.</string>
+ <string name="linked_verified_secret_dns">Es ist alles in Ordnung.</string>
+ <string name="linked_verified_secret_twitter">Es ist alles in Ordnung.</string>
+ <plurals name="linked_id_expand">
+ <item quantity="one">Es gibt einen weiteren unbekannten Identitätstyp</item>
+ <item quantity="other">Es gibt %d weitere unbekannte Identitätstypen</item>
+ </plurals>
+ <!--Other Linked Identity strings-->
+ <string name="linked_select_2">Bitte wähle einen Typ aus:</string>
+ <string name="linked_verifying">Wird verifiziert…</string>
+ <string name="linked_verify_success">Verifiziert!</string>
+ <string name="linked_verify_error">Verifizierungsfehler!</string>
+ <string name="linked_verify_pending">Noch nicht verifiziert</string>
+ <string name="linked_need_verify">Die Ressource muss verifiziert werden bevor du fortfahren kannst!</string>
+ <string name="menu_linked_add_identity">Mit Benutzerkonto verknüpfen</string>
+ <string name="section_linked_identities">Verknüpfte-Identitäten</string>
+ <string name="btn_finish">Abschließen</string>
+ <string name="linked_title_https">Webseite (HTTPS)</string>
+ <string name="linked_title_dns">Domainname (DNS)</string>
+ <string name="linked_title_github">GitHub</string>
+ <string name="linked_title_twitter">Twitter</string>
+ <string name="card_linked_identity">Verknüpfte-Identität</string>
+ <string name="linked_button_verify">Verifizieren</string>
+ <string name="linked_button_retry">Wiederholen</string>
+ <string name="linked_button_confirm">Bestätigen</string>
+ <string name="linked_button_view">Anzeigen</string>
+ <string name="linked_text_verifying">Wird verifiziert...</string>
+ <string name="linked_text_error">Fehler</string>
+ <string name="linked_text_confirming">Wird bestätigt...</string>
+ <string name="linked_ids_more_unknown">%d weitere unbekannte Identitätstypen</string>
+ <string name="title_linked_id_create">Verknüpfte-Identität erzeugen</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-es/strings.xml b/OpenKeychain/src/main/res/values-es/strings.xml
index 043918c64..706c0d226 100644
--- a/OpenKeychain/src/main/res/values-es/strings.xml
+++ b/OpenKeychain/src/main/res/values-es/strings.xml
@@ -4,18 +4,19 @@
http://developer.android.com/guide/topics/resources/string-resource.html (scroll down to "Escaping apostrophes and quotes").-->
<string name="app_name">OpenKeychain</string>
<!--title-->
- <string name="title_encrypt_text">Encriptar</string>
- <string name="title_encrypt_files">Encriptar</string>
+ <string name="title_encrypt_text">Cifrar</string>
+ <string name="title_encrypt_files">Cifrar</string>
<string name="title_decrypt">Descifrar</string>
<string name="title_add_subkey">Añadir subclave</string>
<string name="title_edit_key"> Editar clave</string>
+ <string name="title_linked_create">Crear una identidad vinculada</string>
<string name="title_preferences">Configuración</string>
<string name="title_api_registered_apps">Aplicaciones</string>
<string name="title_key_server_preference">Servidores de claves OpenPGP</string>
<string name="title_change_passphrase">Cambiar contraseña</string>
- <string name="title_share_fingerprint_with">Compartir huella digital con...</string>
+ <string name="title_share_fingerprint_with">Compartir huella de validación con...</string>
<string name="title_share_key">Compartir clave con...</string>
- <string name="title_share_file">Compartir archivo con...</string>
+ <string name="title_share_file">Compartir fichero con...</string>
<string name="title_share_message">Compartir texto con...</string>
<string name="title_encrypt_to_file">Cifrar hacia archivo</string>
<string name="title_decrypt_to_file">Descifrar hacia archivo</string>
@@ -30,35 +31,39 @@
<string name="title_log_display">Registro (log)</string>
<string name="title_exchange_keys">Intercambiar claves</string>
<string name="title_advanced_key_info">Información extendida</string>
- <string name="title_delete_secret_key">¿Borrar clave \'%s\'?</string>
- <string name="title_export_log">Exportar registro (log)</string>
+ <string name="title_delete_secret_key">¿Borrar SU clave \'%s\'?</string>
<string name="title_manage_my_keys">Administrar mis claves</string>
<!--section-->
<string name="section_user_ids">Identificaciones</string>
<string name="section_yubikey">YubiKey</string>
- <string name="section_linked_system_contact">Contacto de sistema enlazado</string>
+ <string name="section_linked_system_contact">Contacto de sistema vinculado</string>
+ <string name="section_keybase_proofs">Comprobantes de keybase.io</string>
<string name="section_should_you_trust">¿Debe confiar en esta clave?</string>
- <string name="section_proof_details">Comprobante de verificación</string>
- <string name="section_cloud_evidence">Comprobantes desde la nube</string>
+ <string name="section_proof_details">Verificación de comprobante</string>
<string name="section_keys">Subclaves</string>
- <string name="section_cloud_search">Búsqueda en la nube</string>
- <string name="section_passphrase_cache">Manejo de contraseña/PIN</string>
- <string name="section_proxy_settings">Configuración para proxy</string>
+ <string name="section_cloud_search">Búsqueda de clave</string>
+ <string name="section_cloud_search_summary">Servidor de claves, keybase.io</string>
+ <string name="section_passphrase_cache">Contraseñas y PINs</string>
+ <string name="section_passphrase_cache_summary">Manejo, interfaz de usuario, periodo de recuerdo</string>
+ <string name="section_proxy_settings">Anonimato en la red</string>
+ <string name="section_proxy_settings_summary">Tor, configuración para proxy</string>
<string name="section_gui">Interfaz</string>
- <string name="section_sync_settings">Sincronizar configuración</string>
+ <string name="section_sync_settings">Sincronización</string>
+ <string name="section_sync_settings_summary">Actualizaciones automáticas de clave, vinculación de contactos</string>
+ <string name="section_experimental_features">Características experimentales</string>
<string name="section_certify">Confirmar</string>
<string name="section_actions">Acciones</string>
<string name="section_share_key">Clave</string>
<string name="section_key_server">Servidor de claves</string>
- <string name="section_fingerprint">Huella digital</string>
- <string name="section_encrypt">Encriptar</string>
+ <string name="section_fingerprint">Huella de validación</string>
+ <string name="section_encrypt">Cifrar</string>
<string name="section_decrypt">Descifrar / Verificar</string>
<string name="section_current_expiry">Caducidad actual</string>
<string name="section_new_expiry">Nueva caducidad</string>
<!--button-->
- <string name="btn_decrypt_verify_file">Desencriptar, verificar, y guardar fichero</string>
- <string name="btn_encrypt_share_file">Encriptar y compartir fichero</string>
- <string name="btn_encrypt_save_file">Encriptar y guardar fichero</string>
+ <string name="btn_decrypt_verify_file">Descifrar, verificar, y guardar fichero</string>
+ <string name="btn_encrypt_share_file">Cifrar y compartir fichero</string>
+ <string name="btn_encrypt_save_file">Cifrar y guardar fichero</string>
<string name="btn_save_file">Guardar fichero</string>
<string name="btn_save">Guardar</string>
<string name="btn_view_log">Ver registro (log)</string>
@@ -70,19 +75,18 @@
<string name="btn_next">Siguiente</string>
<string name="btn_back">Volver</string>
<string name="btn_no">No</string>
- <string name="btn_match">Las huellas digitales coinciden</string>
- <string name="btn_share_encrypted_signed">Encriptar y compartir texto</string>
- <string name="btn_copy_encrypted_signed">Encriptar y copiar texto</string>
- <string name="btn_view_cert_key">Ver clave de verificación</string>
+ <string name="btn_match">Las huellas de validación coinciden</string>
+ <string name="btn_share_encrypted_signed">Cifrar/firmar y compartir texto</string>
+ <string name="btn_copy_encrypted_signed">Cifrar/firmar y copiar texto</string>
+ <string name="btn_view_cert_key">Ver clave de certificación</string>
<string name="btn_create_key">Crear clave</string>
- <string name="btn_add_files">Añadir archivo(s)</string>
- <string name="btn_share_decrypted_text">Compartir texto descifrado</string>
+ <string name="btn_add_files">Añadir fichero(s)</string>
<string name="btn_copy_decrypted_text">Copiar texto descifrado</string>
<string name="btn_decrypt_clipboard">Leer del portapapeles</string>
<string name="btn_decrypt_files">Seleccionar fichero de entrada</string>
- <string name="btn_encrypt_files">Encriptar ficheros</string>
- <string name="btn_encrypt_text">Encriptar texto</string>
- <string name="btn_add_email">Añadir dirección de correo electrónico adicional</string>
+ <string name="btn_encrypt_files">Cifrar ficheros</string>
+ <string name="btn_encrypt_text">Cifrar texto</string>
+ <string name="btn_add_email">Añadir dirección de correo adicional</string>
<string name="btn_unlock">Desbloquear</string>
<string name="btn_add_keyserver">Añadir</string>
<string name="btn_save_default">Guardar como predeterminado</string>
@@ -90,25 +94,23 @@
<!--menu-->
<string name="menu_preferences">Ajustes</string>
<string name="menu_help">Ayuda</string>
- <string name="menu_export_key">Hacer copia de seguridad hacia fichero</string>
<string name="menu_delete_key">Borrar clave</string>
<string name="menu_manage_keys">Administrar mis claves</string>
<string name="menu_search">Buscar</string>
- <string name="menu_nfc_preferences">Configuraciones NFC</string>
+ <string name="menu_nfc_preferences">Ajustes de NFC</string>
<string name="menu_beam_preferences">Ajustes de Beam</string>
<string name="menu_encrypt_to">Cifrar hacia...</string>
<string name="menu_select_all">Seleccionar todo</string>
<string name="menu_export_all_keys">Exportar todas las claves</string>
<string name="menu_update_all_keys">Actualizar todas las claves</string>
<string name="menu_advanced">Información extendida</string>
- <string name="menu_certify_fingerprint">Confirmar mediante comparación de la huella digital</string>
- <string name="menu_export_log">Exportar registro</string>
+ <string name="menu_certify_fingerprint">Confirmar mediante huella de validación</string>
<string name="menu_keyserver_add">Añadir</string>
<!--label-->
<string name="label_message">Texto</string>
<string name="label_file">Archivo</string>
- <string name="label_files">Archivo(s)</string>
- <string name="label_file_colon">Archivo:</string>
+ <string name="label_files">Fichero(s)</string>
+ <string name="label_file_colon">Fichero:</string>
<string name="label_no_passphrase">Sin contraseña</string>
<string name="label_passphrase">Contraseña</string>
<string name="label_unlock">Desbloqueando...</string>
@@ -117,21 +119,19 @@
<string name="label_algorithm">Algoritmo</string>
<string name="label_ascii_armor">Armadura ASCII del fichero</string>
<string name="label_file_ascii_armor">Habilitar armadura ASCII</string>
- <string name="label_write_version_header">Permitir conocer a otros que usted está usando OpenKeychain</string>
+ <string name="label_write_version_header">Permitir a otros conocer que usted está usando OpenKeychain</string>
<string name="label_write_version_header_summary">Escribe \'OpenKeychain v2.7\' en las firmas OpenPGP, texto cifrado, y claves exportadas</string>
- <string name="label_use_default_yubikey_pin">Utilizar PIN predeterminado de la YubiKey</string>
- <string name="label_use_num_keypad_for_yubikey_pin">Utilizar teclado numérico para el PIN de la YubiKey</string>
- <string name="label_label_use_default_yubikey_pin_summary">Utiliza el PIN predeterminado (123456) para acceder a las YubiKeys sobre NFC</string>
+ <string name="label_use_num_keypad_for_yubikey_pin">Usar teclado numérico para el PIN de la YubiKey</string>
<string name="label_asymmetric_from">Firmar con:</string>
<string name="label_to">Cifrar hacia:</string>
- <string name="label_delete_after_encryption">Borrar ficheros después del cifrado</string>
- <string name="label_delete_after_decryption">Eliminar fichero después del descifrado</string>
+ <string name="label_delete_after_encryption">Borrar ficheros tras el cifrado</string>
+ <string name="label_delete_after_decryption">Borrar tras el descifrado</string>
<string name="label_encryption_algorithm">Algoritmo de cifrado</string>
- <string name="label_hash_algorithm">Algoritmo de identificación criptográfica (hash)</string>
+ <string name="label_hash_algorithm">Algoritmo hash</string>
<string name="label_symmetric">Cifrar con contraseña</string>
<string name="label_passphrase_cache_ttl">Recordar hora</string>
<string name="label_passphrase_cache_subs">Recordar contraseñas por subclave</string>
- <string name="label_message_compression">Compresión de texto</string>
+ <string name="label_message_compression">Compresión del texto</string>
<string name="label_file_compression">Compresión del fichero</string>
<string name="label_keyservers">Seleccione servidores de claves OpenPGP</string>
<string name="label_key_id">ID de clave</string>
@@ -141,22 +141,20 @@
<string name="label_usage">Uso</string>
<string name="label_key_size">Tamaño de clave</string>
<string name="label_ecc_curve">Curva elíptica</string>
- <string name="label_main_user_id">Identificación principal</string>
+ <string name="label_main_user_id">Identidad principal</string>
<string name="label_name">Nombre</string>
<string name="label_comment">Comentario</string>
<string name="label_email">Email</string>
- <string name="label_send_key">Sincronizar con la nube</string>
+ <string name="label_send_key">Sincronizar con Internet</string>
<string name="label_fingerprint">Huella digital</string>
<string name="expiry_date_dialog_title">Establer la fecha de vencimiento</string>
<string name="label_keyservers_title">Servidores de claves</string>
- <string name="label_keyserver_settings_hint">Arrastrar para cambiar orden, pulsar para editar/borrar</string>
+ <string name="label_keyserver_settings_hint">Arrastrar para cambiar el orden, pulsar para editar/borrar</string>
<string name="label_selected_keyserver_title">Servidor de claves seleccionado</string>
<string name="label_preferred">preferido</string>
<string name="label_enable_compression">Habilitar compresión</string>
<string name="label_encrypt_filenames">Cifrar nombres de ficheros</string>
- <string name="label_hidden_recipients">Ocultar receptores</string>
- <string name="label_verify_keyserver">Verificar servidor de claves</string>
- <string name="label_enter_keyserver_url">Introduzca URL de servidor de claves</string>
+ <string name="label_hidden_recipients">Ocultar destinatarios</string>
<string name="label_keyserver_dialog_delete">Borrar servidor de claves</string>
<string name="label_theme">Tema decorativo</string>
<string name="pref_keyserver">Servidores de claves OpenPGP</string>
@@ -164,19 +162,26 @@
<string name="pref_keybase">keybase.io</string>
<string name="pref_keybase_summary">Busca claves en keybase.io</string>
<string name="label_sync_settings_keyserver_title">Actualizar claves automáticamente</string>
- <string name="label_sync_settings_keyserver_summary_on">Las claves con más de una semana de vida se actualizarán desde el servidor de claves preferido</string>
+ <string name="label_sync_settings_keyserver_summary_on">Las claves anteriores a una semana se actualizarán desde el servidor de claves preferido</string>
<string name="label_sync_settings_keyserver_summary_off">Las claves no se actualizarán automáticamente</string>
- <string name="label_sync_settings_contacts_title">Sincronizar contactos con claves</string>
- <string name="label_sync_settings_contacts_summary_on">Las claves se vincularon a contactos con correos coincidentes, ocurre de forma completamente desconectada</string>
+ <string name="label_sync_settings_contacts_title">Vincular claves a contactos</string>
+ <string name="label_sync_settings_contacts_summary_on">Vincula claves con contactos basándose en nombres y direcciones de correo electrónico. Esto sucede con su dispositivo completamente desconectado.</string>
<string name="label_sync_settings_contacts_summary_off">Las claves nuevas no se vincularán a contactos</string>
<!--label shown in Android settings under the OpenKeychain account-->
<string name="keyserver_sync_settings_title">Actualizar claves automáticamente</string>
+ <string name="label_experimental_settings_desc_title">Advertencia</string>
+ <string name="label_experimental_settings_desc_summary">Estas características todavía no están finalizadas o no se han obtenido los resultados de experiencia del usuario y la investigación de seguridad. Por tanto, no confíe en su seguridad y, por favor, ¡no informe de los problemas que encuentre!</string>
+ <string name="label_experimental_settings_linked_identities_title">Identidades vinculadas</string>
+ <string name="label_experimental_settings_linked_identities_summary">Vincula claves con Twitter, GitHub, sitios web o DNS (similar a keybase.io pero descentralizado)</string>
+ <string name="label_experimental_settings_keybase_title">Comprobantes de keybase.io</string>
+ <string name="label_experimental_settings_keybase_summary">Contacta con keybase.io para obtener comprobantes de clave y los enseña cada vez que se muestra una clave</string>
+ <string name="label_experimental_settings_theme_summary">(Los iconos y muchas pantallas todavía no están ajustadas a tono con el tema decorativo oscuro)</string>
<!--Proxy Preferences-->
<string name="pref_proxy_tor_title">Habilitar Tor</string>
<string name="pref_proxy_tor_summary">Requiere que Orbot esté instalado</string>
<string name="pref_proxy_normal_title">Habilitar otro proxy</string>
<string name="pref_proxy_host_title">Servidor proxy</string>
- <string name="pref_proxy_host_err_invalid">El servidor proxy (interpuesto) no puede estar vacío</string>
+ <string name="pref_proxy_host_err_invalid">El servidor proxy no puede estar vacío</string>
<string name="pref_proxy_port_title">Puerto de proxy</string>
<string name="pref_proxy_port_err_invalid">Número de puerto introducido no válido</string>
<string name="pref_proxy_type_title">Tipo de proxy</string>
@@ -184,22 +189,18 @@
<string name="pref_proxy_type_choice_http">HTTP</string>
<string name="pref_proxy_type_choice_socks">SOCKS</string>
<!--OrbotHelper strings-->
- <string name="orbot_ignore_tor">No usar Tor</string>
<!--InstallDialogFragment strings-->
<string name="orbot_install_dialog_title">¿Instalar Orbot para usar Tor?</string>
<string name="orbot_install_dialog_install">Instalar</string>
<string name="orbot_install_dialog_content">Tiene que tener Orbot instalado y activado para proxyficar el tráfico a través de él. ¿Desea instalarlo?</string>
<string name="orbot_install_dialog_cancel">Cancelar</string>
- <string name="orbot_install_dialog_ignore_tor">No usar Tor</string>
<!--StartOrbotDialogFragment strings-->
<string name="orbot_start_dialog_title">¿Iniciar Orbot?</string>
- <string name="orbot_start_dialog_content">Orbot no parece estar corriendo. ¿Desea iniciarlo y conectar a Tor?</string>
<string name="orbot_start_btn">Iniciar Orbot</string>
<string name="orbot_start_dialog_start">Iniciar Orbot</string>
<string name="orbot_start_dialog_cancel">Cancelar</string>
- <string name="orbot_start_dialog_ignore_tor">No usar Tor</string>
- <string name="user_id_no_name">&lt;sin nombre&gt;</string>
- <string name="none">&lt;ninguna&gt;</string>
+ <string name="user_id_no_name"><![CDATA[<no name>]]></string>
+ <string name="none"><![CDATA[<none>]]></string>
<plurals name="n_keys">
<item quantity="one">1 clave</item>
<item quantity="other">%d claves</item>
@@ -223,11 +224,12 @@
<string name="choice_4hours">4 horas</string>
<string name="choice_8hours">8 horas</string>
<string name="choice_forever">para siempre</string>
+ <string name="choice_select_cert">Seleccione una clave</string>
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
- <string name="ecdh">ECDH (intercambio Diffie-Hellman con curva elíptica)</string>
- <string name="ecdsa">ECDSA (algoritmo de firma digital con curva elíptica)</string>
+ <string name="ecdh">ECDH</string>
+ <string name="ecdsa">ECDSA</string>
<string name="filemanager_title_open">Abrir...</string>
<string name="error">Error</string>
<string name="error_message">Error: %s</string>
@@ -243,49 +245,45 @@
<string name="no_filemanager_installed">No hay un gestor de archivos compatible instalado.</string>
<string name="passphrases_do_not_match">Las contraseñas no coincidieron.</string>
<string name="passphrase_must_not_be_empty">Introduzca una contraseña.</string>
- <string name="passphrase_for_symmetric_encryption">Cifrado simétrico.</string>
<string name="passphrase_for">Introduzca contraseña para \'%s\'</string>
- <string name="pin_for">Introduzca el PIN para \'%s\'</string>
- <string name="yubikey_pin_for">Introduzca el PIN para acceder a la YubiKey para \'%s\'</string>
+ <string name="pin_for">Introduzca PIN para \'%s\'</string>
+ <string name="yubikey_pin_for">Introduzca PIN para acceder a la YubiKey para \'%s\'</string>
<string name="nfc_text">Sostenga la YubiKey contra el marcador NFC en el reverso de su dispositivo.</string>
<string name="nfc_wait">¡Mantenga la YubiKey en el reverso!</string>
<string name="nfc_finished">Retire la YubiKey ahora.</string>
<string name="nfc_try_again_text">Retire la YubiKey ahora y pulse INTENTAR DE NUEVO.</string>
<string name="file_delete_confirmation_title">¿Borrar ficheros originales?</string>
- <string name="file_delete_confirmation">Los siguientes ficheros se borrarán:%s</string>
+ <string name="file_delete_confirmation">Se borrarán los siguientes ficheros:%s</string>
<string name="file_delete_successful">%1$d de %2$d ficheros han sido borrados.%3$s</string>
- <string name="no_file_selected">Ningún fichero seleccionado.</string>
+ <string name="no_file_selected">No se seleccionó ningún fichero.</string>
<string name="encrypt_sign_successful">Firmado y/o cifrado con éxito.</string>
- <string name="encrypt_sign_clipboard_successful">Firmado y/o cifrado del portapapeles con éxito.</string>
+ <string name="encrypt_sign_clipboard_successful">Firmado y/o cifrado hacia el portapapeles con éxito.</string>
<string name="select_encryption_key">Selecciona al menos una clave de cifrado.</string>
- <string name="error_no_encryption_or_signature_key">Seleccionar al menos una clave de cifrado o una clave de firma.</string>
- <string name="specify_file_to_encrypt_to">Por favor especifique hacia qué fichero cifrar.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
- <string name="specify_file_to_decrypt_to">Por favor especifique hacia qué fichero descifrar.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
- <string name="specify_backup_dest">Se realizará una copia de seguridad excluyendo sus claves, por favor, especifique un fichero de destino.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
- <string name="specify_backup_dest_single">Esta clave se compartirá, por favor, especifique un fichero de destino.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
- <string name="specify_backup_dest_secret_single">Se realizará una copia de seguridad completa de su clave, por favor, especifique un fichero de destino.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
- <string name="specify_backup_dest_secret">Se realizará una copia de seguridad completa de todas sus claves incluyendo las suyas, por favor, especifique un fichero de destino.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
+ <string name="error_no_encryption_or_signature_key">Seleccione al menos una clave de cifrado o una clave de firmado.</string>
+ <string name="specify_file_to_encrypt_to">Especifique hacia qué fichero cifrar.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
+ <string name="specify_file_to_decrypt_to">Especifique hacia qué fichero descifrar.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
+ <string name="specify_backup_dest">Se realizará una copia de seguridad excluyendo sus claves, especifique un fichero de destino.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
+ <string name="specify_backup_dest_single">Esta clave se compartirá, especifique un fichero de destino.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
+ <string name="specify_backup_dest_secret_single">Se realizará una copia de seguridad completa de su clave, especifique un fichero de destino.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
+ <string name="specify_backup_dest_secret">Se realizará una copia de seguridad completa de todas las claves incluyendo las suyas, especifique un fichero de destino.\nADVERTENCIA: ¡El fichero se sobreescribirá si existe!</string>
<string name="key_deletion_confirmation_multi">¿De verdad quiere borrar todas las claves seleccionadas?</string>
- <string name="secret_key_deletion_confirmation">¡Después del borrado no podrá leer mensajes cifrados con esta clave y perderá todas las confirmaciones de clave hechas con ella!</string>
<string name="public_key_deletetion_confirmation">¿Borrar clave \'%s\'?</string>
<string name="also_export_secret_keys">Exportar también claves secretas (privadas)</string>
- <string name="reinstall_openkeychain">Ha encontrado un conocido fallo con Android. Por favor reinstale OpenKeychain si quiere enlazar sus contactos con las claves.</string>
+ <string name="reinstall_openkeychain">Ha encontrado un conocido fallo con Android. Por favor, reinstale OpenKeychain si quiere vincular sus contactos con claves.</string>
<string name="key_exported">Se ha exportado 1 clave satisfactoriamente.</string>
<string name="keys_exported">%d claves exportadas satisfactoriamente.</string>
<string name="no_keys_exported">No se han exportado claves.</string>
<string name="key_creation_el_gamal_info">Nota: Sólo las subclaves soportan ElGamal.</string>
<string name="key_not_found">No se puede encontrar la clave %08X.</string>
- <string name="specify_file_to_export_log_to">Por favor especifique el fichero al que exportar. \nADVERTENCIA: El fichero se sobreescribirá si existe.</string>
<plurals name="bad_keys_encountered">
- <item quantity="one">%d clave secreta (privada) defectuosa ignorada. Quizá exportó con la opción\n --export-secret-subkeys\nAsegúrese de que exporta con\n --export-secret-keys\nen su lugar.\"</item>
- <item quantity="other">%d claves secretas (privadas) defectuosas ignoradas. Quizá exportó con la opción\n --export-secret-subkeys\nAsegúrese de que exporta con\n --export-secret-keys\nen su lugar.\"</item>
+ <item quantity="one">%d clave secreta (privada) errónea ignorada. Quizá exportó con la opción\n --export-secret-subkeys\nAsegúrese de que exporta con\n --export-secret-keys\nen su lugar.\"</item>
+ <item quantity="other">%d claves secretas (privadas) erróneas ignoradas. Quizá exportó con la opción\n --export-secret-subkeys\nAsegúrese de que exporta con\n --export-secret-keys\nen su lugar.\"</item>
</plurals>
<string name="list_empty">¡Esta lista está vacía!</string>
- <string name="nfc_successful">¡Clave enviada con éxito vía NFC Beam (haz NFC)!</string>
+ <string name="nfc_successful">¡Clave enviada con éxito vía NFC Beam!</string>
<string name="key_copied_to_clipboard">¡La clave ha sido copiada al portapapeles!</string>
<string name="fingerprint_copied_to_clipboard">¡La huella de validación de clave se ha copiado al portapapeles!</string>
<string name="select_key_to_certify">¡Por favor seleccione una clave a usar para confirmación!</string>
- <string name="key_too_big_for_sharing">¡La clave es demasiado grande para ser compartida de esta forma!</string>
<string name="text_copied_to_clipboard">¡El texto se ha copiado al portapapeles!</string>
<!--errors
no punctuation, all lowercase,
@@ -297,28 +295,28 @@
<string name="error_external_storage_not_ready">el almacenamiento externo no está preparado</string>
<string name="error_key_size_minimum512bit">el tamaño de clave debe ser de al menos 512bit</string>
<string name="error_unknown_algorithm_choice">elegido algoritmo desconocido</string>
- <string name="error_user_id_no_email">no se encontró ninguna dirección de correo</string>
- <string name="error_key_needs_a_user_id">necesita al menos una identificación</string>
- <string name="error_no_signature_passphrase">no se estableció contraseña.</string>
+ <string name="error_user_id_no_email">no se encontró ninguna dirección de email</string>
+ <string name="error_key_needs_a_user_id">necesita al menos una identidad</string>
+ <string name="error_no_signature_passphrase">no proporcionó contraseña</string>
<string name="error_no_signature_key">no has proporcionado una clave de firma</string>
<string name="error_invalid_data">¡No es un contenido cifrado o firmado con OpenPGP válido!</string>
<string name="error_integrity_check_failed">¡ha fallado la comprobación de integridad! ¡Los datos han sido modificados!</string>
<string name="error_wrong_passphrase">contraseña incorrecta</string>
<string name="error_could_not_extract_private_key">no se puede extraer la clave privada</string>
<!--errors without preceeding Error:-->
- <string name="error_jelly_bean_needed">¡Necesita Android 4.1 para usar la característica NFC Beam (haz NFC) de Android!</string>
- <string name="error_nfc_needed">¡NFC ha de estar habilitado!</string>
- <string name="error_beam_needed">¡Beam ha de estar habilitado!</string>
+ <string name="error_jelly_bean_needed">¡Necesita Android 4.1 para usar la característica NFC Beam de Android!</string>
+ <string name="error_nfc_needed">¡NFC debe estar habilitado!</string>
+ <string name="error_beam_needed">¡Beam debe estar habilitado!</string>
<string name="error_nothing_import">¡No se encontraron claves!</string>
<string name="error_nothing_import_selected">¡No se seleccionaron claves a importar!</string>
- <string name="error_contacts_key_id_missing">¡Fallo al obtener clave de identificación desde los contactos!</string>
+ <string name="error_contacts_key_id_missing">¡Fallo al obtener la clave de la identidad de los contactos!</string>
<string name="error_generic_report_bug">Ha ocurrido un error genérico, por favor, informa de este bug a OpenKeychain</string>
<!--results shown after decryption/verification-->
<string name="decrypt_result_no_signature">No firmado</string>
<string name="decrypt_result_invalid_signature">¡Firma no válida!</string>
<string name="decrypt_result_insecure_cryptography">¡Firma no válida (criptografía no segura)!</string>
<string name="decrypt_result_signature_uncertified">Firmado por clave <b>no confirmada</b></string>
- <string name="decrypt_result_signature_secret">Firmado por la clave de usted</string>
+ <string name="decrypt_result_signature_secret">Firmado por su clave</string>
<string name="decrypt_result_signature_certified">Firmado por clave confirmada</string>
<string name="decrypt_result_signature_expired_key">¡Firmado por clave <b>caducada</b>!</string>
<string name="decrypt_result_signature_revoked_key">¡Firmado por clave <b>revocada</b>!</string>
@@ -328,8 +326,8 @@
<string name="decrypt_result_insecure">Cifrado no seguro</string>
<string name="decrypt_result_action_show">Mostrar</string>
<string name="decrypt_result_action_Lookup">Buscar</string>
- <string name="decrypt_invalid_text">O bien la firma no es válida o la clave ha sido revocada. No puede estar seguro de quién escribió el texto. ¿Quiere aún mostrarlo?</string>
- <string name="decrypt_invalid_button">Comprendo los riesgos, ¡muéstralo!</string>
+ <string name="decrypt_invalid_text">O bien la firma no es válida o la clave ha sido revocada. No puede estar seguro de quién escribió el texto. ¿Aún quiere mostrarlo?</string>
+ <string name="decrypt_invalid_button">Comprendo los riesgos, ¡mostrarlo!</string>
<!--Add keys-->
<string name="add_keys_my_key">Mi clave:</string>
<!--progress dialogs, usually ending in '…'-->
@@ -351,13 +349,13 @@
<string name="progress_generating_ecdh">generando nueva clave ECDH...</string>
<string name="progress_modify">modificando juego de claves...</string>
<string name="progress_modify_unlock">desbloqueando juego de claves...</string>
- <string name="progress_modify_adduid">añadiendo identificaciones de usuario...</string>
+ <string name="progress_modify_adduid">añadiendo identidades de usuario...</string>
<string name="progress_modify_adduat">añadiendo atributos de usuario...</string>
<string name="progress_modify_revokeuid">revocando identificaciones de usuario...</string>
- <string name="progress_modify_primaryuid">cambiando identificación principal de usuario...</string>
+ <string name="progress_modify_primaryuid">cambiando identidad principal de usuario...</string>
<string name="progress_modify_subkeychange">modificando subclaves...</string>
<string name="progress_modify_subkeyrevoke">revocando subclaves...</string>
- <string name="progress_modify_subkeystrip">desnudando claves...</string>
+ <string name="progress_modify_subkeystrip">desnudando subclaves...</string>
<string name="progress_modify_subkeyadd">añadiendo subclaves...</string>
<string name="progress_modify_passphrase">cambiando contraseña...</string>
<string name="progress_modify_pin">cambiando PIN...</string>
@@ -373,8 +371,8 @@
<string name="progress_encrypting">cifrando los datos...</string>
<string name="progress_decrypting">descifrando los datos...</string>
<string name="progress_preparing_signature">preparando la firma...</string>
- <string name="progress_generating_signature">generando la firma...</string>
<string name="progress_processing_signature">procesando la firma...</string>
+ <string name="progress_generating_signature">generando la firma...</string>
<string name="progress_verifying_signature">verificando la firma...</string>
<string name="progress_signing">firmando...</string>
<string name="progress_certifying">certificando...</string>
@@ -384,17 +382,12 @@
<string name="progress_verifying_integrity">verificando la integridad...</string>
<string name="progress_deleting_securely">borrando \'%s\' de forma segura…</string>
<string name="progress_deleting">borrando claves...</string>
- <string name="progress_con_saving">consolidación: guardando en caché...</string>
- <string name="progress_con_reimport">consolidación: reimportando</string>
- <string name="progress_verifying_keyserver_url">verificando servidor de claves...</string>
+ <string name="progress_con_saving">consolidar: guardando en caché...</string>
+ <string name="progress_con_reimport">consolidar: reimportando...</string>
<string name="progress_starting_orbot">Iniciando Orbot...</string>
<!--action strings-->
- <string name="hint_cloud_search_hint">Buscar mediante Nombre, Correo electrónico...</string>
+ <string name="hint_cloud_search_hint">Buscar mediante nombre, email...</string>
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -424,29 +417,29 @@
<string name="help_about_version">Versión:</string>
<!--Import-->
<string name="import_tab_keyserver">Servidor de claves</string>
- <string name="import_tab_cloud">Buscar en la nube</string>
+ <string name="import_tab_cloud">Búsqueda de clave</string>
<string name="import_tab_direct">Fichero/Portapapeles</string>
<string name="import_tab_qr_code">Código QR/NFC</string>
<string name="import_import">Importar las claves seleccionadas</string>
<string name="import_qr_code_wrong">¡El código QR está deformado! ¡Por favor, prueba de nuevo!</string>
- <string name="import_qr_code_fp">¡La huella de validación de clave está malformada o es demasiado corta!</string>
+ <string name="import_qr_code_fp">¡La huella de validación de clave está mal formada o es demasiado corta!</string>
<string name="import_qr_code_too_short_fingerprint">¡La huella de validación de clave es demasiado corta!</string>
<string name="import_qr_code_button">Escanear código QR</string>
<string name="import_qr_code_text">¡Sitúe su cámara sobre el código QR!</string>
<!--Import from URL-->
- <string name="import_url_warn_no_search_parameter">No se definió consulta de búsqueda. Aún puede buscar manualmente en este servidor de claves.</string>
+ <string name="import_url_warn_no_search_parameter">No se definió criterio de búsqueda. Aún puede buscar manualmente en este servidor de claves.</string>
<!--Generic result toast-->
<string name="snackbar_details">Detalles</string>
<string name="with_warnings">, con advertencias</string>
- <string name="with_cancelled">, hasta que sea cancelado</string>
+ <string name="with_cancelled">, hasta cancelación</string>
<!--Import result toast-->
<plurals name="import_keys_added_and_updated_1">
- <item quantity="one">Clave importada con éxito</item>
- <item quantity="other">%1$d claves importadas con éxito</item>
+ <item quantity="one">Se importó con éxito una clave</item>
+ <item quantity="other">Se importaron con éxito %1$d claves</item>
</plurals>
<plurals name="import_keys_added_and_updated_2">
- <item quantity="one">y actualizada clave%2$s.</item>
- <item quantity="other">y actualizadas %1$d claves%2$s.</item>
+ <item quantity="one">y se actualizó una clave%2$s.</item>
+ <item quantity="other">y se actualizaron %1$d claves%2$s.</item>
</plurals>
<plurals name="import_keys_added">
<item quantity="one">Clave%2$s importada con éxito.</item>
@@ -457,8 +450,8 @@
<item quantity="other">%1$d claves%2$s actualizadas con éxito.</item>
</plurals>
<plurals name="import_keys_with_errors">
- <item quantity="one">¡Fallo al importar una clave!</item>
- <item quantity="other">¡Fallo al importar %d claves!</item>
+ <item quantity="one">¡La importación falló para una clave!</item>
+ <item quantity="other">¡La importación fallo para %d claves!</item>
</plurals>
<plurals name="import_error">
<item quantity="one">¡Fallo al importar!</item>
@@ -492,8 +485,8 @@
<string name="revoke_cancelled">Se canceló la operación de revocado.</string>
<!--Certify result toast-->
<plurals name="certify_keys_ok">
- <item quantity="one">Clave%2$s certificada con éxito.</item>
- <item quantity="other">%1$d claves%2$s certificadas con éxito.</item>
+ <item quantity="one">Se confirmó una clave%2$s con éxito.</item>
+ <item quantity="other">Se confirmaron %1$d claves%2$s con éxito.</item>
</plurals>
<plurals name="certify_keys_with_errors">
<item quantity="one">¡La certificación falló!</item>
@@ -511,8 +504,8 @@
<!--Remote API-->
<string name="api_settings_show_info">Mostrar información extendida</string>
<string name="api_settings_hide_info">Ocultar información extendida</string>
- <string name="api_settings_show_advanced">Mostrar configuración extendida</string>
- <string name="api_settings_hide_advanced">Ocultar configuración extendida</string>
+ <string name="api_settings_show_advanced">Mostrar ajustes extendidos</string>
+ <string name="api_settings_hide_advanced">Ocultar ajustes extendidos</string>
<string name="api_settings_no_key">No se ha seleccionado ninguna clave</string>
<string name="api_settings_select_key">Seleccionar clave</string>
<string name="api_settings_create_key">Crear nueva clave</string>
@@ -529,19 +522,19 @@
<string name="api_settings_allowed_keys">Claves permitidas</string>
<string name="api_settings_settings">Configuración</string>
<string name="api_settings_key">Clave de la cuenta:</string>
- <string name="api_settings_accounts_empty">No hay cuentas adjuntas a esta aplicación</string>
- <string name="api_create_account_text">No se ha configurado clave para esta cuenta. Por favor seleccione una entre sus claves existentes o cree una nueva.\n¡Las aplicaciones sólo pueden descifrar/firmar con las claves que seleccione aquí!</string>
- <string name="api_update_account_text">La clave guardada para esta cuenta ha sido borrada. ¡Por favor seleccione una diferente!\n¡Las aplicaciones sólo pueden firmar/descifrar con las claves seleccionadas aquí!</string>
- <string name="api_register_text">La aplicación mostrada quiere cifrar/descifrar mensajes y firmarlos en su nombre.\n¿Permitir acceso?\n\nADVERTENCIA: Si no sabe por qué apareció esta pantalla, ¡no permita el acceso! Puede revocar el acceso más tarde usando la pantalla \'Aplicaciones\'.</string>
+ <string name="api_settings_accounts_empty">No hay cuentas adjuntas a esta aplicación.</string>
+ <string name="api_create_account_text">No se ha configurado clave para esta cuenta. Seleccione una entre sus claves existentes o cree una nueva.\n¡Las aplicaciones sólo pueden descifrar/firmar con las claves que seleccione aquí!</string>
+ <string name="api_update_account_text">La clave guardada para esta cuenta ha sido borrada. ¡Seleccione una diferente!\n¡Las aplicaciones sólo pueden firmar/descifrar con las claves seleccionadas aquí!</string>
+ <string name="api_register_text">La aplicación mostrada quiere cifrar/descifrar mensajes y firmarlos en su nombre.\n¿Permitir acceso?\n\nADVERTENCIA: ¡Si no sabe por qué apareció esta pantalla, no permita el acceso! Puede revocar el acceso más tarde usando la pantalla \'Aplicaciones\'.</string>
<string name="api_register_allow">Permitir el acceso</string>
<string name="api_register_disallow">Denegar el acceso</string>
<string name="api_register_error_select_key">¡Por favor, selecciona una clave!</string>
<string name="api_select_pub_keys_missing_text">No se encontraron claves para estas direcciones de correo electrónico:</string>
<string name="api_select_pub_keys_dublicates_text">Existe más de una clave para estas direcciones de correo electrónico:</string>
<string name="api_select_pub_keys_text">¡Por favor, revisa la lista de destinatarios!</string>
- <string name="api_select_pub_keys_text_no_user_ids">¡Por favor seleccione los receptores!</string>
+ <string name="api_select_pub_keys_text_no_user_ids">¡Por favor, seleccione los destinatarios!</string>
<string name="api_error_wrong_signature">¡La comprobación de la firma ha fallado! ¿Has instalado esta app desde una fuente distinta? Si estás seguro de que esto no es un ataque, revoca el registro de esta app en OpenKeychain y regístrala de nuevo.</string>
- <string name="api_select_sign_key_text">Por favor, seleccione una de sus claves existentes o cree una nueva.</string>
+ <string name="api_select_sign_key_text">Seleccione una de sus claves existentes o cree una nueva.</string>
<string name="api_select_keys_text">Ninguna de las claves permitidas puede descifrar el contenido. Por favor, seleccione las claves permitidas.</string>
<!--Share-->
<string name="share_qr_code_dialog_title">Compartir con código QR</string>
@@ -566,7 +559,10 @@
</plurals>
<string name="key_list_empty_text1">¡No se encontraron claves!</string>
<string name="key_list_filter_show_all">Mostrar todas las claves</string>
- <string name="key_list_filter_show_certified">Mostrar sólo claves certificadas</string>
+ <string name="key_list_filter_show_certified">Mostrar sólo claves confirmadas</string>
+ <string name="key_list_fab_qr_code">Escanear código QR</string>
+ <string name="key_list_fab_search">Búsqueda de clave</string>
+ <string name="key_list_fab_import">Importar desde fichero</string>
<!--Key view-->
<string name="key_view_action_edit">Editar clave</string>
<string name="key_view_action_encrypt">Cifrar texto</string>
@@ -582,24 +578,17 @@
<string name="key_view_tab_certs">Certificados</string>
<string name="key_view_tab_keybase">Keybase.io</string>
<string name="user_id_info_revoked_title">Revocada</string>
- <string name="user_id_info_revoked_text">Esta identificación ha sido revocada por el propietario de la clave. En adelante no será válida.</string>
- <string name="user_id_info_certified_title">Certificada</string>
- <string name="user_id_info_certified_text">Esta identificación ha sido certificada por usted.</string>
- <string name="user_id_info_uncertified_title">No certificada</string>
- <string name="user_id_info_uncertified_text">Esta identificación de no ha sido certificada aún. No puede estar seguro de si la identificación corresponde en realidad a una persona específica.</string>
+ <string name="user_id_info_revoked_text">Esta identidad ha sido revocada por el propietario de la clave. Ya no es válida.</string>
+ <string name="user_id_info_certified_title">Confirmada</string>
+ <string name="user_id_info_certified_text">Esta identidad ha sido confirmada por usted.</string>
+ <string name="user_id_info_uncertified_title">No confirmada</string>
+ <string name="user_id_info_uncertified_text">Esta identidad aún no ha sido confirmada. No puede estar seguro de si la identidad corresponde realmente a una persona específica.</string>
<string name="user_id_info_invalid_title">No válida</string>
- <string name="user_id_info_invalid_text">¡Hay algo mal con esta identificación!</string>
+ <string name="user_id_info_invalid_text">¡Hay algo mal con esta identidad!</string>
<!--Key trust-->
- <string name="key_trust_already_verified">¡Ya ha confirmado esta clave!</string>
- <string name="key_trust_it_is_yours">¡Esta es una de sus claves!</string>
- <string name="key_trust_maybe">Esta clave no está revocada ni ha caducado.\nNo la ha confirmado, pero puede elegir confiar en ella.</string>
- <string name="key_trust_revoked">Esta clave ha sido revocada por su propietario. No debe confiar en ella.</string>
- <string name="key_trust_expired">Esta clave ha caducado. No debe confiar en ella.</string>
- <string name="key_trust_old_keys">Puede ser correcto utilizar esta para descifrar un mensaje antiguo que data del momento en que esta clave era válida.</string>
- <string name="key_trust_no_cloud_evidence">No hay comprobantes desde la nube sobre la confiabilidad de esta clave.</string>
- <string name="key_trust_start_cloud_search">Comenzar búsqueda</string>
+ <string name="key_trust_no_cloud_evidence">No hay comprobante desde Internet de la confiabilidad de esta clave.</string>
+ <string name="key_trust_start_cloud_search">Iniciar búsqueda</string>
<string name="key_trust_results_prefix">Keybase.io ofrece \"comprobantes\" que sostienen que el propietario de esta clave:</string>
- <string name="key_trust_header_text">Nota: Los comprobantes de Keybase.io son una característica experimental de OpenKeychain. Le animamos a que escanee los Códigos QR o intercambie claves vía NFC además de confirmarlas.</string>
<!--keybase proof stuff-->
<string name="keybase_narrative_twitter">Publica en Twitter como %s</string>
<string name="keybase_narrative_github">Es conocido en GitHub como %s</string>
@@ -608,82 +597,79 @@
<string name="keybase_narrative_reddit">Publica en Reddit como %s</string>
<string name="keybase_narrative_coinbase">Es conocido en Coinbase como %s</string>
<string name="keybase_narrative_hackernews">Publica en Hacker News como %s</string>
- <string name="keybase_narrative_unknown">Prueba de tipo desconocido %s</string>
+ <string name="keybase_narrative_unknown">Comprobante de tipo desconocido %s</string>
<string name="keybase_proof_failure">Desafortunadamente este comprobante no se puede verificar.</string>
- <string name="keybase_unknown_proof_failure">Problema no reconocido con el chequeador del comprobante</string>
+ <string name="keybase_unknown_proof_failure">Problema no reconocido con el verificador del comprobante</string>
<string name="keybase_problem_fetching_evidence">Problema con el comprobante</string>
- <string name="keybase_key_mismatch">La huella de validación de clave no coincide con aquella en el post del comprobante</string>
- <string name="keybase_dns_query_failure">Fallo al obtener registro DNS TXT</string>
- <string name="keybase_no_prover_found">No se encontró chequeador del comprobante</string>
+ <string name="keybase_key_mismatch">La huella de validación de clave no coincide con la del post del comprobante</string>
+ <string name="keybase_dns_query_failure">Fallo al obtener el registro TXT del DNS</string>
+ <string name="keybase_no_prover_found">No se encontró verificador del comprobante para </string>
<string name="keybase_message_payload_mismatch">El post del comprobante descrifrado no coincide con el valor esperado</string>
<string name="keybase_message_fetching_data">Descargando comprobante</string>
<string name="keybase_proof_succeeded">¡Este comprobante ha sido verificado!</string>
<string name="keybase_a_post">Un post</string>
- <string name="keybase_fetched_from">descargada desde</string>
+ <string name="keybase_fetched_from">descargado de</string>
<string name="keybase_for_the_domain">para el dominio</string>
<string name="keybase_contained_signature">contiene un mensaje que sólo podría haber sido creado por el propietario de esta clave.</string>
<string name="keybase_twitter_proof">Un twit</string>
- <string name="keybase_dns_proof">Un registro DNS TXT</string>
+ <string name="keybase_dns_proof">Un registro TXT del DNS</string>
<string name="keybase_web_site_proof">Un fichero de texto</string>
- <string name="keybase_github_proof">Un gist</string>
+ <string name="keybase_github_proof">Un Gist</string>
<string name="keybase_reddit_proof">Un fichero JSON</string>
<string name="keybase_reddit_attribution">atribuido por Reddit a</string>
<string name="keybase_verify">Verificar</string>
<!--Edit key-->
<string name="edit_key_action_change_passphrase">Cambiar contraseña</string>
- <string name="edit_key_action_add_identity">Añadir identificación</string>
+ <string name="edit_key_action_add_identity">Añadir identidad</string>
<string name="edit_key_action_add_subkey">Añadir subclave</string>
<string name="edit_key_edit_user_id_title">¡Seleccione una acción!</string>
<string-array name="edit_key_edit_user_id">
- <item>Cambiar a identificación principal</item>
- <item>Revocar identificación</item>
+ <item>Cambiar a identidad principal</item>
+ <item>Revocar identidad</item>
</string-array>
<string-array name="edit_key_edit_user_id_revert_revocation">
<item>Revertir revocación</item>
</string-array>
- <string name="edit_key_edit_user_id_revoked">Esta identificación se ha revocado. Esto no puede deshacerse.</string>
+ <string name="edit_key_edit_user_id_revoked">Esta identidad se ha revocado. Esto no se puede deshacer.</string>
<string name="edit_key_edit_subkey_title">¡Seleccione una acción!</string>
<string-array name="edit_key_edit_subkey">
<item>Cambiar caducidad</item>
<item>Revocar subclave</item>
<item>Desnudar subclave</item>
- <item>Mover subclave a la Yubikey / Tarjeta inteligente</item>
+ <item>Mover subclave a la Yubikey / tarjeta inteligente</item>
</string-array>
<string name="edit_key_new_subkey">nueva subclave</string>
<string name="edit_key_select_flag">¡Por favor, seleccione al menos un indicador!</string>
- <string name="edit_key_error_add_identity">¡Añadir al menos una identificación!</string>
+ <string name="edit_key_error_add_identity">¡Añada al menos una identidad!</string>
<string name="edit_key_error_add_subkey">¡Añadir al menos una subclave!</string>
<string name="edit_key_error_bad_nfc_algo">¡Algoritmo no soportado por la tarjeta inteligente!</string>
<string name="edit_key_error_bad_nfc_size">¡El tamaño de la clave no está soportado por la tarjeta inteligente!</string>
<string name="edit_key_error_bad_nfc_stripped">¡No se puede mover la clave a la tarjeta inteligente (tanto desnuda como \'derivar-a-tarjeta\')!</string>
<!--Create key-->
- <string name="create_key_upload">Sincronizar con la nube</string>
+ <string name="create_key_upload">Sincronizar con Internet</string>
<string name="create_key_empty">Este campo es obligatorio</string>
<string name="create_key_passphrases_not_equal">Las contraseñas no coinciden</string>
- <string name="create_key_final_text">Ha introducido la siguiente identificación:</string>
+ <string name="create_key_final_text">Ha introducido la siguiente identidad :</string>
<string name="create_key_final_robot_text">Crear una clave puede llevar un tiempo, tómese una taza de café entre tanto...</string>
<string name="create_key_rsa">(3 subclaves, RSA, 4096 bits)</string>
<string name="create_key_custom">(configuración de clave personalizada)</string>
<string name="create_key_name_text">Elija un nombre asociado con esta clave. Este puede ser un nombre completo, ej. \'Juan Nadie\', o un apodo, ej. \'Juanito\'.</string>
<string name="create_key_email_text">Introduzca su dirección principal de correo electrónico para comunicación segura.</string>
- <string name="create_key_passphrase_text">Escoja una contraseña robusta. Protegerá su clave si su dispositivo es robado.</string>
+ <string name="create_key_passphrase_text">Escoja una contraseña robusta. Protegerá su clave si su dispositivo resulta robado.</string>
<string name="create_key_hint_full_name">Nombre completo o apodo</string>
<string name="create_key_edit">Cambiar configuración de clave</string>
<string name="create_key_add_email">Añadir dirección de correo electrónico</string>
- <string name="create_key_add_email_text">Las direcciones adicionales de correo electrónico también están asociadas a esta clave y pueden utilizarse para asegurar la comunicación.</string>
- <string name="create_key_email_already_exists_text">Esta dirección de correo electrónico ya fue añadida</string>
+ <string name="create_key_add_email_text">Las direcciones adicionales de correo también están asociadas a esta clave y pueden utilizarse para asegurar la comunicación.</string>
+ <string name="create_key_email_already_exists_text">Esta dirección de correo ya fue añadida</string>
<string name="create_key_email_invalid_email">El formato de la dirección de correo no es válido</string>
- <string name="create_key_yubi_key_pin_text">Por favor, recuerde el PIN, se requiere para usar su YubiKey más tarde. Por favor, escriba el PIN de Admin y guárdelo en un lugar seguro.</string>
<string name="create_key_yubi_key_pin">PIN</string>
<string name="create_key_yubi_key_admin_pin">PIN de Admin</string>
- <string name="create_key_yubi_key_pin_repeat_text">Por favor, introduzca el PIN y el PIN de Admin para proceder.</string>
<string name="create_key_yubi_key_pin_repeat">Repita el PIN</string>
- <string name="create_key_yubi_key_admin_pin_repeat">Repita el PIN de Admin</string>
<string name="create_key_yubi_key_pin_not_correct">¡El PIN no es correcto!</string>
<!--View key-->
- <string name="view_key_revoked">Revocada: ¡La clave no debe volver a ser usada!</string>
- <string name="view_key_expired">Caducada: ¡El contacto necesita extender la vigencia de la clave!</string>
- <string name="view_key_expired_secret">Caducada: ¡Puede extender la vigencia de las claves al editarlas!</string>
+ <string name="view_key_revoked">Revocada: ¡La clave no se debe volver a usar!</string>
+ <string name="view_key_expired">Caducada: ¡El contacto necesita extender la validez de la clave!</string>
+ <string name="view_key_expired_secret">Caducada: ¡Puede extender la validez de las claves editándolas!</string>
<string name="view_key_my_key">Mi clave</string>
<string name="view_key_verified">Clave confirmada</string>
<string name="view_key_unverified">No confirmada: ¡Escanee el código QR para confirmar clave!</string>
@@ -691,10 +677,9 @@
<!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Añadir servidor de claves</string>
<string name="edit_keyserver_dialog_title">Editar servidor de claves</string>
- <string name="add_keyserver_verified">¡Servidor de claves verificado!</string>
<string name="add_keyserver_without_verification">Servidor de claves añadido sin verificación</string>
<string name="add_keyserver_invalid_url">¡URL no válida!</string>
- <string name="add_keyserver_connection_failed">Fallo al conectar al servidor de claves. Por favor, compuebe la URL y su conexión a Internet.</string>
+ <string name="add_keyserver_connection_failed">No se pudo conectar al servidor de claves. Por favor, compruebe la URL y su conexión a Internet.</string>
<string name="keyserver_preference_deleted">%s borrado</string>
<string name="keyserver_preference_cannot_delete_last">No se puede borrar el último servidor de claves. ¡Se requiere al menos uno!</string>
<!--Navigation Drawer-->
@@ -704,16 +689,15 @@
<string name="drawer_open">Abrir el Navigation Drawer</string>
<string name="drawer_close">Cerrar el Navigation Drawer</string>
<string name="my_keys">Mis claves</string>
- <string name="nav_backup">Copia de seguridad</string>
<!--hints-->
<string name="encrypt_content_edit_text_hint">Escriba el texto</string>
<!--certs-->
- <string name="cert_default">predeterminado</string>
- <string name="cert_none">ninguno</string>
- <string name="cert_casual">casual</string>
- <string name="cert_positive">positivo</string>
+ <string name="cert_default">predeterminada</string>
+ <string name="cert_none">ninguna</string>
+ <string name="cert_casual">informal</string>
+ <string name="cert_positive">positiva</string>
<string name="cert_revoke">revocada</string>
- <string name="cert_verify_ok">Correcto</string>
+ <string name="cert_verify_ok">correcto</string>
<string name="cert_verify_failed">¡falló!</string>
<string name="cert_verify_error">¡error!</string>
<string name="cert_verify_unavailable">clave no disponible</string>
@@ -721,8 +705,8 @@
<string name="msg_internal_error">¡Error interno!</string>
<string name="msg_cancelled">Operación cancelada.</string>
<!--Import Public log entries-->
- <string name="msg_ip_apply_batch">Aplicando operación de inserción por lote.</string>
- <string name="msg_ip_bad_type_secret">Se intentó importar un juego de claves (keyring) secreto como público. Esto es un fallo, por favor ¡consigne un informe!</string>
+ <string name="msg_ip_apply_batch">Aplicando operación de inserción en lote.</string>
+ <string name="msg_ip_bad_type_secret">Se intentó importar un juego de claves secretas (privadas) como públicas. Esto es un fallo, por favor ¡consigne un informe!</string>
<string name="msg_ip_delete_old_fail">No se borró ninguna clave antigua (¿crear una nueva?)</string>
<string name="msg_ip_delete_old_ok">Clave antigua borrada de la base de datos</string>
<string name="msg_ip_encode_fail">La operación falló debido a un error de codificación</string>
@@ -730,7 +714,7 @@
<string name="msg_ip_error_op_exc">La operación falló debido a un error de la base de datos</string>
<string name="msg_ip_error_remote_ex">La operación falló debido a un error interno</string>
<string name="msg_ip">Importando juego de claves públicas %s</string>
- <string name="msg_ip_insert_keyring">Codificando datos del juego de claves (keyring)</string>
+ <string name="msg_ip_insert_keyring">Codificando datos del juego de claves</string>
<string name="msg_ip_insert_keys">Analizando claves</string>
<string name="msg_ip_prepare">Preparando base de datos de operaciones</string>
<string name="msg_ip_master">Procesando clave maestra %s</string>
@@ -753,8 +737,8 @@
<string name="msg_ip_master_flags_xxsx">Indicativos maestros: firmar</string>
<string name="msg_ip_master_flags_xxxa">Indicativos maestros: autentificar</string>
<string name="msg_ip_master_flags_xxxx">Indicativos maestros: ninguno</string>
- <string name="msg_ip_merge_public">Incorporando datos importados al juego de claves público existente</string>
- <string name="msg_ip_merge_secret">Incorporando datos importados al juego de claves público existente</string>
+ <string name="msg_ip_merge_public">Incorporando datos importados al juego de claves públicas existente</string>
+ <string name="msg_ip_merge_secret">Incorporando datos importados al juego de claves secretas (privadas) existente</string>
<string name="msg_ip_subkey">Procesando subclave %s</string>
<string name="msg_ip_subkey_expired">La subclave caducó el %s</string>
<string name="msg_ip_subkey_expires">La subclave caduca el %s</string>
@@ -765,7 +749,7 @@
<string name="msg_ip_subkey_flags_cexx">Indicativos de subclave: certificar, cifrar</string>
<string name="msg_ip_subkey_flags_cxsa">Indicativos de subclave: certificar, firmar, autentificar</string>
<string name="msg_ip_subkey_flags_cxsx">Indicativos de subclave: certificar, firmar</string>
- <string name="msg_ip_subkey_flags_cxxa">Indicativos de subclaves: certificar, autentificar</string>
+ <string name="msg_ip_subkey_flags_cxxa">Indicativos de subclave: certificar, autentificar</string>
<string name="msg_ip_subkey_flags_cxxx">Indicativos de subclave: certificar</string>
<string name="msg_ip_subkey_flags_xesa">Indicativos de subclave: cifrar, firmar, autentificar</string>
<string name="msg_ip_subkey_flags_xesx">Indicativos de subclave: cifrar, firmar</string>
@@ -777,159 +761,158 @@
<string name="msg_ip_subkey_flags_xxxx">Indicativos de subclave: ninguno</string>
<string name="msg_ip_success">Juego de claves públicas importado con éxito</string>
<string name="msg_ip_success_identical">El juego de claves no contiene nuevos datos, no hay nada que hacer</string>
- <string name="msg_ip_reinsert_secret">Re-insertando clave secreta</string>
- <string name="msg_ip_uid_cert_bad">¡Se encontró un certificado defectuoso!</string>
+ <string name="msg_ip_reinsert_secret">Re-insertando clave secreta (privada)</string>
+ <string name="msg_ip_uid_cert_bad">¡Se encontró un certificado erróneo!</string>
<string name="msg_ip_uid_cert_error">¡Error procesando certificado!</string>
<string name="msg_ip_uid_cert_nonrevoke">Ya tiene un certificado no-revocable, omitiendo.</string>
<string name="msg_ip_uid_cert_old">El certificado es más antiguo que el anterior, omitiendo.</string>
<string name="msg_ip_uid_cert_new">El certificado es más reciente, reemplazando el anterior.</string>
- <string name="msg_ip_uid_cert_good">Se encontró un certificado correcto por %1$s</string>
- <string name="msg_ip_uid_cert_good_revoke">Se encontró un certificado de revocación correcto por %1$s</string>
+ <string name="msg_ip_uid_cert_good">Se encontró un certificado correcto emitido por %1$s</string>
+ <string name="msg_ip_uid_cert_good_revoke">Se encontró un certificado de revocación correcto emitido por %1$s</string>
<plurals name="msg_ip_uid_certs_unknown">
<item quantity="one">Ignorando un certificado publicado por una clave pública desconocida</item>
<item quantity="other">Ignorando %s certificados publicados por claves públicas desconocidas</item>
</plurals>
- <string name="msg_ip_uid_classifying_zero">Clasificando identificaciones de usuario (no hay disponibles claves de confianza)</string>
+ <string name="msg_ip_uid_classifying_zero">Clasificando identidades de usuario (no hay claves de confianza disponibles)</string>
<plurals name="msg_ip_uid_classifying">
- <item quantity="one">Clasificando identificaciones de usuario (usando una clave de confianza)</item>
- <item quantity="other">Clasificando identificaciones de usuario (usando %s claves de confianza)</item>
+ <item quantity="one">Clasificando identidades de usuario (usando una clave de confianza)</item>
+ <item quantity="other">Clasificando identidades de usuario (usando %s claves de confianza)</item>
</plurals>
- <string name="msg_ip_uid_reorder">Re-ordenando identificaciones de usuario</string>
- <string name="msg_ip_uid_processing">Procesando identificación de usuario %s</string>
- <string name="msg_ip_uid_revoked">La identificación de usuario está revocada</string>
+ <string name="msg_ip_uid_reorder">Re-ordenando identidades de usuario</string>
+ <string name="msg_ip_uid_processing">Procesando identidad %s de usuario</string>
+ <string name="msg_ip_uid_revoked">La identidad de usuario está revocada</string>
<string name="msg_ip_uat_processing_image">Procesando atributo de usuario de tipo imagen</string>
<string name="msg_ip_uat_processing_unknown">Procesando atributo de usuario de tipo desconocido</string>
- <string name="msg_ip_uat_cert_bad">¡Se encontró un certificado defectuoso!</string>
+ <string name="msg_ip_uat_cert_bad">¡Se encontró un certificado erróneo!</string>
<string name="msg_ip_uat_cert_error">¡Error procesando certificado!</string>
<string name="msg_ip_uat_cert_nonrevoke">Ya tiene un certificado no revocable, omitiendo.</string>
<string name="msg_ip_uat_cert_old">El certificado es más antiguo que el anterior, omitiendo.</string>
<string name="msg_ip_uat_cert_new">El certificado es más reciente, reemplazando el anterior.</string>
- <string name="msg_ip_uat_cert_good">Hallado certificado correcto por %1$s</string>
- <string name="msg_ip_uat_cert_good_revoke">Hallada revocación de certificado correcta por %1$s </string>
+ <string name="msg_ip_uat_cert_good">Hallado certificado correcto emitido por %1$s</string>
+ <string name="msg_ip_uat_cert_good_revoke">Hallada revocación de certificado correcta emitida por %1$s </string>
<plurals name="msg_ip_uat_certs_unknown">
<item quantity="one">Ignorando un certificado publicado por una clave pública desconocida</item>
<item quantity="other">Ignorando %s certificados publicados por claves públicas desconocidas</item>
</plurals>
<string name="msg_ip_uat_classifying">Clasificando atributos de usuario</string>
<string name="msg_ip_uat_revoked">El atributo de usuario está revocado</string>
- <string name="msg_is_bad_type_public">Se intentó importar un juego de claves (keyring) público como secreto. Esto es un fallo, por favor ¡consigne un informe!</string>
- <string name="msg_is_bad_type_uncanon">Se intentó importar un juego de claves sin canonicalización. ¡Esto es un fallo, por favor rellene un informe!</string>
+ <string name="msg_is_bad_type_public">Se intentó importar un juego de claves públicas como secretas (privadas). Esto es un fallo, por favor ¡consigne un informe!</string>
+ <string name="msg_is_bad_type_uncanon">Se intentó importar un juego de claves sin canonicalización. Esto es un fallo, por favor, ¡consigne un informe!</string>
<!--Import Secret log entries-->
<string name="msg_is">Importando clave secreta (privada) %s</string>
<string name="msg_is_db_exception">¡Error de base de datos!</string>
- <string name="msg_is_importing_subkeys">Procesando subclaves secretas</string>
- <string name="msg_is_error_io_exc">Error codificando el juego de claves (keyring)</string>
+ <string name="msg_is_importing_subkeys">Procesando subclaves secretas (privadas)</string>
+ <string name="msg_is_error_io_exc">Error codificando el juego de claves</string>
<string name="msg_is_merge_public">Incorporando datos importados al juego de claves público existente</string>
- <string name="msg_is_merge_secret">Incorporando datos importados al juego de claves público existente</string>
- <string name="msg_is_merge_special">Incorporando datos de auto-certificados desde el juego de claves público</string>
+ <string name="msg_is_merge_secret">Incorporando datos importados al juego de claves secretas (privadas) existente.</string>
+ <string name="msg_is_merge_special">Incorporando datos de auto-certificados desde el juego de claves públicas</string>
<string name="msg_is_pubring_generate">Generando un juego de claves públicas desde el juego de claves secretas (privadas)</string>
<string name="msg_is_subkey_nonexistent">La subclave %s no está disponible en la clave secreta (privada)</string>
<string name="msg_is_subkey_ok">Subclave secreta (privada) %s marcada como disponible</string>
- <string name="msg_is_subkey_empty">Subclave secreta %s marcada como disponible, con contraseña vacía</string>
- <string name="msg_is_subkey_pin">Subclave secreta %s marcada como disponible, con PIN</string>
+ <string name="msg_is_subkey_empty">Subclave secreta (privada) %s marcada como disponible, con contraseña vacía</string>
+ <string name="msg_is_subkey_pin">Subclave secreta (privada) %s marcada como disponible, con PIN</string>
<string name="msg_is_subkey_stripped">Subclave secreta (privada) %s marcada como desnuda</string>
<string name="msg_is_subkey_divert">Se marcó la subclave sercreta (privada) %s como \'derivar-a-tarjeta\'</string>
<string name="msg_is_success_identical">El juego de claves no contiene nuevos datos, no hay nada que hacer</string>
<string name="msg_is_success">Juego de claves secretas (privadas) importado con éxito</string>
<!--Keyring Canonicalization log entries-->
- <string name="msg_kc_public">Canonicalizando juego de claves público %s</string>
- <string name="msg_kc_secret">Canonicalizando juego de claves secreto %s</string>
+ <string name="msg_kc_public">Canonicalizando el juego de claves públicas %s</string>
+ <string name="msg_kc_secret">Canonicalizando el juego de claves secretas (privadas) %s</string>
<string name="msg_kc_error_v3">¡Esta es una clave OpenPGP versión 3, que ha sido desechada y ya no está soportada!</string>
- <string name="msg_kc_error_no_uid">¡El juego de claves no tiene identificaciones de usuario válidas!</string>
+ <string name="msg_kc_error_no_uid">¡El juego de claves no tiene identidades de usuario válidas!</string>
<string name="msg_kc_error_master_algo">¡La clave maestra usa un algoritmo (%s) desconocido!</string>
- <string name="msg_kc_error_dup_key">La subclave %s aparece dos veces en el juego de claves (keyring). El juego de claves está mal formado, ¡no se va a importar!</string>
+ <string name="msg_kc_error_dup_key">La subclave %s aparece dos veces en el juego de claves. El juego está mal formado, ¡no se va a importar!</string>
<string name="msg_kc_master">Procesando clave maestra</string>
<string name="msg_kc_master_bad_type">Eliminando certificado de clave maestra de tipo desconocido (%s)</string>
- <string name="msg_kc_master_bad_local">Eliminando certificado de clave maestra con distintivo \'local\'</string>
- <string name="msg_kc_master_bad_err">Eliminando certificado de clave maestra defectuoso</string>
- <string name="msg_kc_master_bad_time">Eliminando certificado de revocación de juego de claves con marca de tiempo en el futuro</string>
- <string name="msg_kc_master_bad_type_uid">Eliminando certificado de identificación de usuario en posición incorrecta</string>
- <string name="msg_kc_master_bad">Eliminando certificado de clave maestra defectuoso</string>
- <string name="msg_kc_master_local">Eliminando certificado de clave maestra con distintitivo \'local\'</string>
- <string name="msg_kc_revoke_dup">Eliminando certificado redundante de revocación de juego de claves </string>
- <string name="msg_kc_notation_dup">Eliminando certificado de notación redundante</string>
- <string name="msg_kc_notation_empty">Eliminando certificado de notación vacía</string>
+ <string name="msg_kc_master_bad_local">Eliminando certificado con indicativo \'local\' de clave maestra </string>
+ <string name="msg_kc_master_bad_err">Eliminando certificado de clave maestra erróneo</string>
+ <string name="msg_kc_master_bad_time">Eliminando certificado de revocación de juego de claves con marca de tiempo futura</string>
+ <string name="msg_kc_master_bad_type_uid">Eliminando certificado de identidad de usuario en posición incorrecta</string>
+ <string name="msg_kc_master_bad">Eliminando certificado de clave maestra erróneo</string>
+ <string name="msg_kc_master_local">Eliminando certificado con indicativo \'local\' de clave maestra</string>
+ <string name="msg_kc_revoke_dup">Eliminando certificado redundante de revocación de juego de claves</string>
+ <string name="msg_kc_notation_dup">Eliminando certificado redundante de notación</string>
+ <string name="msg_kc_notation_empty">Eliminando certificado de notación vacío</string>
<string name="msg_kc_sub">Procesando subclave %s</string>
- <string name="msg_kc_sub_bad">Eliminando certificado no vigente de vinculación de subclave</string>
- <string name="msg_kc_sub_bad_err">Eliminando certificado defectuoso de vinculación de subclave</string>
- <string name="msg_kc_sub_bad_local">Eliminando certificado de vinculación de subclave con distintivo \'local\'</string>
- <string name="msg_kc_sub_bad_keyid">La identificación del publicante de la vinculación de subclave no coincide</string>
- <string name="msg_kc_sub_bad_time">Eliminando certificado de vinculación de subclave, con marca de tiempo futura</string>
- <string name="msg_kc_sub_bad_time_early">¡El certificado de acoplamiento de subclave tiene una marca de tiempo anterior a su clave!</string>
+ <string name="msg_kc_sub_bad">Eliminando certificado de asignación de subclave no válido</string>
+ <string name="msg_kc_sub_bad_err">Eliminando certificado de asignación de subclave erróneo </string>
+ <string name="msg_kc_sub_bad_local">Eliminando certificado con indicativo \'local\' de asignación de subclave</string>
+ <string name="msg_kc_sub_bad_keyid">La identidad del emisor del certificado de asignación de la subclave no coincide</string>
+ <string name="msg_kc_sub_bad_time">Eliminando certificado de asignación de subclave con marca de tiempo futura</string>
+ <string name="msg_kc_sub_bad_time_early">¡El certificado de asignación de la subclave tiene una marca de tiempo anterior a la clave de la que depende!</string>
<string name="msg_kc_sub_bad_type">Tipo de certificado de subclave desconocido: %s</string>
- <string name="msg_kc_sub_dup">Eliminando certificado redundante de vinculación de subclave</string>
- <string name="msg_kc_sub_primary_bad">Eliminando certificado de vinculación de subclave debido a un certificado de vinculación principal no vigente</string>
- <string name="msg_kc_sub_primary_bad_err">Eliminando certificado de vinculación de subclave debido a un certificado de vinculación principal defectuoso</string>
- <string name="msg_kc_sub_primary_none">Eliminando certificado de vinculación de subclave debido a un certificado de vinculación principal ausente</string>
- <string name="msg_kc_sub_no_cert">No se encontró ningún certificado vigente para %s, eliminándola del juego de claves</string>
- <string name="msg_kc_sub_revoke_bad_err">Eliminando certificado defectuoso de revocación de subclave</string>
- <string name="msg_kc_sub_revoke_bad">Eliminando certificado defectuoso de revocación de subclave</string>
+ <string name="msg_kc_sub_dup">Eliminando certificado redundante de asignación de subclave</string>
+ <string name="msg_kc_sub_primary_bad">Eliminando certificado de asignación de subclave debido a que el certificado de asignación principal no es válido</string>
+ <string name="msg_kc_sub_primary_bad_err">Eliminando certificado de asignación de subclave debido a que el certificado de asignación principal es erróneo</string>
+ <string name="msg_kc_sub_primary_none">Eliminando certificado de asignación de subclave debido a que falta el certificado de asignación principal</string>
+ <string name="msg_kc_sub_no_cert">No se encontró ningún certificado válido para %s, eliminándola del juego de claves</string>
+ <string name="msg_kc_sub_revoke_bad_err">Eliminando certificado erróneo de revocación de subclave</string>
+ <string name="msg_kc_sub_revoke_bad">Eliminando certificado erróneo de revocación de subclave</string>
<string name="msg_kc_sub_revoke_dup">Eliminando certificado redundante de revocación de subclave</string>
<string name="msg_kc_sub_unknown_algo">La subclave usa un algoritmo desconocido, no se va a importar...</string>
<string name="msg_kc_sub_algo_bad_encrpyt">La subclave tiene un indicativo de uso para cifrado, pero el algoritmo no es adecuado para cifrado.</string>
- <string name="msg_kc_sub_algo_bad_sign">La subclave tiene un indicativo de uso para firma, pero el algoritmo no es adecuado para firma.</string>
- <string name="msg_kc_success">Canonicalización del juego de claves exitosa, no hay cambios</string>
+ <string name="msg_kc_sub_algo_bad_sign">La subclave tiene un indicativo de uso para firmado, pero el algoritmo no es adecuado para firma.</string>
+ <string name="msg_kc_success">Canonicalización del juego de claves completada, no hay cambios</string>
<plurals name="msg_kc_success_bad">
- <item quantity="one">Canonicalización de juego de claves completada, se eliminó un certificado erróneo</item>
- <item quantity="other">Canonicalización de juego de claves completada, se eliminaron %d certificados erróneos</item>
+ <item quantity="one">Canonicalización del juego de claves completada, se eliminó un certificado erróneo</item>
+ <item quantity="other">Canonicalización del juego de claves completada, se eliminaron %d certificados erróneos</item>
</plurals>
- <string name="msg_kc_success_bad_and_red">Canonicalización de juego de claves completada, eliminados %1$s certificados erróneos y %2$s redundantes </string>
+ <string name="msg_kc_success_bad_and_red">Canonicalización del juego de claves completada, eliminado(s) %1$s certificado(s) erróneo(s) y %2$s redundante(s)</string>
<plurals name="msg_kc_success_redundant">
- <item quantity="one">Canonicalización de juego de claves completada, se eliminó un certificado redundante</item>
- <item quantity="other">Canonicalización de juego de claves completada, se eliminaron %d certificados redundantes</item>
+ <item quantity="one">Canonicalización del juego de claves completada, se eliminó un certificado redundante</item>
+ <item quantity="other">Canonicalización del juego de claves completada, se eliminaron %d certificados redundantes</item>
</plurals>
- <string name="msg_kc_uid_bad_err">Eliminando auto certificado defectuoso para la identificación de usuario \'%s\'</string>
- <string name="msg_kc_uid_bad_local">Eliminando certificado de identificación de usuario con indicativo \'local\'</string>
- <string name="msg_kc_uid_bad_time">Eliminando identificación de usuario con marca de tiempo en futuro</string>
- <string name="msg_kc_uid_bad_type">Eliminando certificado de identificación de usuario de tipo desconocido (%s)</string>
- <string name="msg_kc_uid_bad">Eliminando auto certificado defectuoso para la identificación de usuario \'%s\'</string>
- <string name="msg_kc_uid_cert_dup">Eliminando auto certificado caducado para la identificación de usuario \'%s\'</string>
- <string name="msg_kc_uid_foreign">Eliminando certificado por \'%s\' de identificación de usuario ajeno </string>
- <string name="msg_kc_uid_revoke_dup">Eliminando certificado de revocación redundante para la identificación de usuario \'%s\'</string>
- <string name="msg_kc_uid_revoke_old">Eliminando certificado de revocación caducado para la identificación de usuario \'%s\'</string>
- <string name="msg_kc_uid_no_cert">No se encontró auto-certificado vigente para la identificación de usuario \'%s\', eliminándola del juego de claves</string>
- <string name="msg_kc_uid_remove">Eliminando identificación de usuario \'%s\' no válida</string>
- <string name="msg_kc_uid_dup">Eliminando identificaciones de usuario duplicadas \'%s\'. El juego de claves contenía dos de ellas. ¡Esto puede resultar en certificados perdidos!</string>
- <string name="msg_kc_uid_warn_encoding">¡La identificación de usuario no se confirma como UTF-8!</string>
- <string name="msg_kc_uat_jpeg">Procesando atributo de usuario del tipo JPEG</string>
+ <string name="msg_kc_uid_bad_err">Eliminando auto-certificado erróneo para la identidad \'%s\' de usuario</string>
+ <string name="msg_kc_uid_bad_local">Eliminando certificado con indicativo \'local\' de identidad de usuario</string>
+ <string name="msg_kc_uid_bad_time">Eliminando certificado de identidad de usuario con marca de tiempo futura</string>
+ <string name="msg_kc_uid_bad_type">Eliminando certificado de identidad de usuario de tipo desconocido (%s)</string>
+ <string name="msg_kc_uid_bad">Eliminando auto-certificado erróneo para la identidad \'%s\' de usuario</string>
+ <string name="msg_kc_uid_cert_dup">Eliminando auto-certificado desactualizado para la identidad \'%s\' de usuario</string>
+ <string name="msg_kc_uid_foreign">Eliminando certificado ajeno de identidad de usuario emitido por \'%s\'</string>
+ <string name="msg_kc_uid_revoke_dup">Eliminando certificado redundante de revocación para la identidad \'%s\' de usuario</string>
+ <string name="msg_kc_uid_revoke_old">Eliminando certificado de revocación desactualizado para la identidad \'%s\' de usuario</string>
+ <string name="msg_kc_uid_no_cert">No se encontró auto-certificado válido para la identificación \'%s\' de usuario, eliminándola del juego de claves</string>
+ <string name="msg_kc_uid_remove">Eliminando identidad \'%s\' de usuario no válida</string>
+ <string name="msg_kc_uid_dup">Eliminando identidades \'%s\' de usuario duplicadas. El juego de claves contenía dos de ellas. ¡Esto puede resultar en certificados perdidos!</string>
+ <string name="msg_kc_uid_warn_encoding">¡La identidad de usuario no se verifica con codificación UTF-8!</string>
+ <string name="msg_kc_uat_jpeg">Procesando atributo de usuario de tipo JPEG</string>
<string name="msg_kc_uat_unknown">Procesando atributo de usuario de tipo desconocido</string>
- <string name="msg_kc_uat_bad_err">Eliminando auto certificados defectuosos para el atributo de usuario</string>
- <string name="msg_kc_uat_bad_local">Eliminando certificado de atributo de usuario con indicativo \'local\'</string>
+ <string name="msg_kc_uat_bad_err">Eliminando auto-certificado erróneo para el atributo de usuario</string>
+ <string name="msg_kc_uat_bad_local">Eliminando certificado con indicativo \'local\' del atributo de usuario </string>
<string name="msg_kc_uat_bad_time">Eliminando atributo de usuario con marca de tiempo futura</string>
- <string name="msg_kc_uat_bad_type">Eliminando certificado de atributo de usuario de tipo desconocido (%s)</string>
- <string name="msg_kc_uat_bad">Eliminando auto certificado defectuoso para el atributo de usuario</string>
- <string name="msg_kc_uat_cert_dup">Eliminando auto certificado desactualizado para el atributo de usuario</string>
+ <string name="msg_kc_uat_bad_type">Eliminando certificado del atributo de usuario de tipo desconocido (%s)</string>
+ <string name="msg_kc_uat_bad">Eliminando auto-certificado erróneo para el atributo de usuario</string>
+ <string name="msg_kc_uat_cert_dup">Eliminando auto-certificado desactualizado para el atributo de usuario</string>
<string name="msg_kc_uat_dup">Eliminando atributo de usuario duplicado. El juego de claves contenía dos de ellos. ¡Esto puede resultar en certificados perdidos!</string>
<string name="msg_kc_uat_foreign">Eliminando atributo de usuario ajeno certificado por</string>
- <string name="msg_kc_uat_revoke_dup">Eliminando certificado de revocación redundante para el atributo de usuario</string>
+ <string name="msg_kc_uat_revoke_dup">Eliminando certificado redundante de revocación para el atributo de usuario</string>
<string name="msg_kc_uat_revoke_old">Eliminando certificado de revocación desactualizado para el atributo de usuario</string>
- <string name="msg_kc_uat_no_cert">No se encontró auto certificado válido para el atributo de usuario, eliminándolo del juego de claves</string>
+ <string name="msg_kc_uat_no_cert">No se encontró auto-certificado válido para el atributo de usuario, eliminándolo del juego de claves</string>
<string name="msg_kc_uat_remove">Eliminando atributo de usuario no válido</string>
- <string name="msg_kc_uat_warn_encoding">¡La identificación de usuario no se confirma como UTF-8!</string>
+ <string name="msg_kc_uat_warn_encoding">¡La identidad de usuario no se confirma como UTF-8!</string>
<!--Keyring merging log entries-->
<string name="msg_mg_error_secret_dummy">Nueva subclave pública encontrada, ¡pero la generación de subclaves secretas (privadas) ficticias no está soportada!</string>
<string name="msg_mg_error_heterogeneous">¡Se intentaron fusionar juegos de claves con diferentes huellas de validación de claves!</string>
<string name="msg_mg_error_encode">¡Error fatal codificando firma!</string>
<string name="msg_mg_public">Incorporándolas en el juego de claves públicas %s</string>
- <string name="msg_mg_secret">Incorporándolas en el juego de claves secretas (privadas) %s</string>
+ <string name="msg_mg_secret">Incorporando al juego de claves secretas (privadas) %s</string>
<string name="msg_mg_new_subkey">Añadiendo nueva subclave %s</string>
<string name="msg_mg_found_new">Se encontraron %s nuevos certificados en el juego de claves</string>
<string name="msg_mg_unchanged">Nada que incorporar</string>
<!--createSecretKeyRing-->
<string name="msg_cr">Generando nueva clave maestra</string>
<string name="msg_cr_error_no_master">¡No se especificaron opciones de clave!</string>
- <string name="msg_cr_error_no_user_id">¡Los juegos de claves tienen que crearse con al menos una identificación de usuario!</string>
+ <string name="msg_cr_error_no_user_id">¡Los juegos de claves tienen que crearse con al menos una identidad de usuario!</string>
<string name="msg_cr_error_no_certify">¡La clave maestra debe tener el indicador de certificado!</string>
- <string name="msg_cr_error_null_expiry">El periodo hasta la expiración no puede ser \'el mismo que antes\' al crear clave. Esto es un error de programación, ¡por favor consigne un informe de error!</string>
- <string name="msg_cr_error_keysize_512">¡El tamaño de la clave debe ser mayor o igual de 512!</string>
- <string name="msg_cr_error_no_curve">¡No se especificó tamaño de clave! ¡Esto es un error de programación, por favor consigne un informe de fallo!</string>
- <string name="msg_cr_error_no_keysize">¡No se especificó curva elíptica! ¡Esto es un error de programación, por favor consigne un informe de fallo!</string>
+ <string name="msg_cr_error_null_expiry">El periodo de caducidad no puede ser \'el mismo que antes\' al crear una clave. Esto es un error de programación, por favor, ¡consigne un informe de fallo!</string>
+ <string name="msg_cr_error_no_curve">¡No se especificó tamaño de clave! Esto es un error de programación, por favor, ¡consigne un informe de fallo!</string>
+ <string name="msg_cr_error_no_keysize">¡No se especificó curva elíptica! Esto es un error de programación, por favor, ¡consigne un informe de fallo!</string>
<string name="msg_cr_error_internal_pgp">¡Error OpenPGP interno!</string>
- <string name="msg_cr_error_unknown_algo">¡Se seleccionó un algoritmo desconocido! ¡Esto es un error de programación, por favor consigne un informe de errores!</string>
- <string name="msg_cr_error_flags_dsa">¡Se seleccionaron indicativos de clave defectuosa, DSA no puede usarse para cifrado!</string>
- <string name="msg_cr_error_flags_elgamal">¡Se seleccionaron indicativos de clave defectuosa, ElGamal no puede usarse para firmado!</string>
- <string name="msg_cr_error_flags_ecdsa">¡Se seleccionaron indicativos de clave defectuosa, ECDSA no puede usarse para cifrado!</string>
- <string name="msg_cr_error_flags_ecdh">¡Seleccionados indicativos de clave defectuosa, ECDH no puede usarse para firmado!</string>
+ <string name="msg_cr_error_unknown_algo">¡Se seleccionó un algoritmo desconocido! Esto es un error de programación, por favor, ¡consigne un informe de fallo!</string>
+ <string name="msg_cr_error_flags_dsa">¡Se seleccionaron indicativos erróneos de clave, DSA no se puede usar para cifrado!</string>
+ <string name="msg_cr_error_flags_elgamal">¡Se seleccionaron indicativos erróneos de clave, ElGamal no se puede usar para firmado!</string>
+ <string name="msg_cr_error_flags_ecdsa">¡Se seleccionaron indicativos erróneos de clave, ECDSA no se puede usar para cifrado!</string>
+ <string name="msg_cr_error_flags_ecdh">¡Seleccionados indicativos erróneos de clave, ECDH no se puede usar para firmado!</string>
<!--modifySecretKeyRing-->
<string name="msg_mr">Modificando el juego de claves %s</string>
<string name="msg_mf_divert">Se derivará a la tarjeta inteligente para operaciones de criptografía</string>
@@ -937,16 +920,16 @@
<string name="msg_mf_error_divert_serial">¡El número de serie de una clave \'derivar-a-tarjeta\' ha de tener 16 bytes! Esto es un error de programación, por favor, ¡consigne un infome de fallo!</string>
<string name="msg_mf_error_encode">¡Excepción en la codificación!</string>
<string name="msg_mf_error_fingerprint">¡La actual huella de validación de clave no coincide con la esperada!</string>
- <string name="msg_mf_error_keyid">No hay identificación de clave. Esto es un error interno, por favor ¡consigne un informe de error!</string>
+ <string name="msg_mf_error_keyid">No hay identidad (ID) de clave. Esto es un error interno, por favor, ¡consigne un informe de fallo!</string>
<string name="msg_mf_error_integrity">Error interno, ¡fallo en la comprobación de integridad!</string>
<string name="msg_mf_error_master_none">¡No se encontró certificado maestro sobre el que operar! (¿Todos revocados?)</string>
- <string name="msg_mf_error_noexist_primary">¡Se especificó una identificación de usuario principal errónea!</string>
- <string name="msg_mf_error_noexist_revoke">¡Se especificó una identificación de usuario errónea para revocación!</string>
- <string name="msg_mf_error_restricted">¡Se intentó ejecutar una operación restringida sin contraseña! Este es un error de programación, por favor, ¡consigne un informe de fallo!</string>
+ <string name="msg_mf_error_noexist_primary">¡Se especificó una identidad principal de usuario errónea!</string>
+ <string name="msg_mf_error_noexist_revoke">¡Se especificó una identidad de usuario para revocación errónea!</string>
+ <string name="msg_mf_error_restricted">¡Se intentó ejecutar una operación restringida sin contraseña! Esto es un error de programación, por favor, ¡consigne un informe de fallo!</string>
<string name="msg_mf_error_revoked_primary">¡Las identificaciones de usuario revocadas no pueden ser las principales!</string>
- <string name="msg_mf_error_null_expiry">El periodo hasta la expiración no puede ser \"el mismo que antes\" al crear subclave. Esto es un error de programación, por favor ¡rellene un informe de fallo!</string>
+ <string name="msg_mf_error_null_expiry">El periodo caducidad no puede ser \"el mismo de antes\" al crear una subclave. Esto es un error de programación, por favor ¡consigne un informe de fallo!</string>
<string name="msg_mf_error_noop">¡No hay nada que hacer!</string>
- <string name="msg_mf_error_passphrase_master">¡Error fatal descrifrando la clave maestra! Probablemente esto se daba a un error de programación, por favor ¡rellene un informe de fallo!</string>
+ <string name="msg_mf_error_passphrase_master">¡Error fatal descrifrando la clave maestra! Probablemente esto sea un error de programación, por favor ¡consigne un informe de fallo!</string>
<string name="msg_mf_error_pgp">¡Error OpenPGP interno!</string>
<string name="msg_mf_error_sig">¡Excepción con la firma!</string>
<string name="msg_mf_error_sub_stripped">¡No se pueden modificar subclaves desnudas %s!</string>
@@ -963,24 +946,24 @@
<string name="msg_mf_passphrase_key">Re-cifrando subclave %s con la nueva contraseña</string>
<string name="msg_mf_passphrase_empty_retry">El establecimiento de la nueva contraseña falló, volviéndolo a intentar con una contraseña antigua vacía.</string>
<string name="msg_mf_passphrase_fail">¡La contraseña para la subclave no se pudo cambiar! (¿Tiene una contraseña diferente a la del resto de las claves?)</string>
- <string name="msg_mf_primary_replace_old">Reemplazando certificado de la identificación de usuario principal anterior</string>
- <string name="msg_mf_primary_new">Generando nuevo certificado para nueva identificación de usuario primaria</string>
+ <string name="msg_mf_primary_replace_old">Reemplazando certificado de la anterior identidad principal de usuario</string>
+ <string name="msg_mf_primary_new">Generando nuevo certificado para nueva identidad principal de usuario</string>
<string name="msg_mf_restricted_mode">Cambiando al modo de operación restringido</string>
<string name="msg_mf_subkey_change">Modificando subclave %s</string>
<string name="msg_mf_require_divert">Derivando a la tarjeta inteligente para operaciones de criptografía</string>
<string name="msg_mf_require_passphrase">Contraseña requerida para operaciones</string>
<string name="msg_mf_subkey_new">Añadiendo nueva subclave de tipo %s</string>
- <string name="msg_mf_subkey_new_id">Nueva identificación de subclave: %s</string>
- <string name="msg_mf_error_past_expiry">¡La fecha de expiración no puede ser del pasado!</string>
+ <string name="msg_mf_subkey_new_id">Nueva identidad de subclave: %s</string>
+ <string name="msg_mf_error_past_expiry">¡La fecha de caducidad no puede ser del pasado!</string>
<string name="msg_mf_subkey_revoke">Revocando subclave %s</string>
<string name="msg_mf_subkey_strip">Desnudando subclave %s</string>
<string name="msg_mf_keytocard_start">Moviendo subclave %s a la tarjeta inteligente</string>
<string name="msg_mf_keytocard_finish">Se movió %1$s a la tarjeta inteligente %2$s</string>
<string name="msg_mf_success">Juego de claves modificado con éxito</string>
- <string name="msg_mf_uid_add">Añadiendo identificación de usuario %s</string>
- <string name="msg_mf_uid_primary">Cambiando identificación de usuario primaria a %s</string>
- <string name="msg_mf_uid_revoke">Revocando la identificación de usuario %s</string>
- <string name="msg_mf_uid_error_empty">¡La identificación de usuario no debe estar vacía!</string>
+ <string name="msg_mf_uid_add">Añadiendo identidad %s de usuario</string>
+ <string name="msg_mf_uid_primary">Cambiando identidad principal de usuario a %s</string>
+ <string name="msg_mf_uid_revoke">Revocando identidad %s de usuario</string>
+ <string name="msg_mf_uid_error_empty">¡La identidad de usuario no debe estar vacía!</string>
<string name="msg_mf_uat_error_empty">¡El atributo de usuario no debe estar vacío!</string>
<string name="msg_mf_uat_add_image">Añadiendo atributo de usuario de tipo imagen</string>
<string name="msg_mf_uat_add_unknown">Añadiendo atributo de usuario de tipo desconocido</string>
@@ -988,7 +971,7 @@
<string name="msg_mf_unlock">Desbloqueando juego de claves (keyring)</string>
<!--Consolidate-->
<string name="msg_con">Consolidando base de datos</string>
- <string name="msg_con_error_bad_state">¡La consolidación se inició cuando ninguna base de datos estaba cacheada! Probablemente esto es un error de programación, por favor consigne un informe de fallo.</string>
+ <string name="msg_con_error_bad_state">¡La consolidación se inició cuando ninguna base de datos estaba en caché! Probablemente esto es un error de programación, por favor, consigne un informe de fallo.</string>
<string name="msg_con_error_concurrent">¡Consolidación abortada, ejecutándose ya en otro hilo!</string>
<string name="msg_con_save_secret">Guardando juegos de claves secretas (privadas)</string>
<string name="msg_con_save_public">Guardando juegos de claves públicas</string>
@@ -996,8 +979,8 @@
<string name="msg_con_success">Base de datos consolidada con éxito</string>
<string name="msg_con_critical_in">Entrando en fase crítica</string>
<string name="msg_con_critical_out">Abandonando fase crítica</string>
- <string name="msg_con_delete_public">Borrando fichero de caché de juego de claves públicas</string>
- <string name="msg_con_delete_secret">Borrando fichero de caché de juego de claves secretas (privadas)</string>
+ <string name="msg_con_delete_public">Borrando fichero de caché del juego de claves públicas</string>
+ <string name="msg_con_delete_secret">Borrando fichero de caché del juego de claves secretas (privadas)</string>
<string name="msg_con_error_db">¡Error al abrir la base de datos!</string>
<string name="msg_con_error_io_public">¡Error de E/S al escribir claves públicas en caché!</string>
<string name="msg_con_error_io_secret">¡Error de E/S al escribir claves secretas (privadas) en caché!</string>
@@ -1016,8 +999,8 @@
<item quantity="other">Reimportando %d claves secretas (privadas)</item>
</plurals>
<string name="msg_con_reimport_secret_skip">No hay claves públicas a reimportar, omitiendo...</string>
- <string name="msg_con_warn_delete_public">Excepción borrando fichero de caché de claves públicas</string>
- <string name="msg_con_warn_delete_secret">Excepción al borrar fichero de caché de claves secretas (privadas)</string>
+ <string name="msg_con_warn_delete_public">Excepción al borrar el fichero de caché de claves públicas</string>
+ <string name="msg_con_warn_delete_secret">Excepción al borrar el fichero de caché de claves secretas (privadas)</string>
<!--Edit Key (higher level than modify)-->
<string name="msg_ed">Realizando operación en la clave</string>
<string name="msg_ed_caching_new">Guardando en caché la nueva contraseña</string>
@@ -1044,10 +1027,10 @@
<string name="msg_dc_charset">Se encontró cabecera de juego de caracteres: \'%s\'</string>
<string name="msg_dc_clear_data">Procesando datos literales</string>
<string name="msg_dc_clear_decompress">Desempaquetando datos comprimidos</string>
- <string name="msg_dc_clear_meta_file">Nombre de fichero: %s</string>
+ <string name="msg_dc_clear_meta_file">Nombre del fichero: %s</string>
<string name="msg_dc_clear_meta_mime">Tipo MIME: %s</string>
- <string name="msg_dc_clear_meta_size">Tamaño de fichero: %s</string>
- <string name="msg_dc_clear_meta_size_unknown">Tamaño de fichero desconocido</string>
+ <string name="msg_dc_clear_meta_size">Tamaño del fichero: %s</string>
+ <string name="msg_dc_clear_meta_size_unknown">Tamaño del fichero desconocido</string>
<string name="msg_dc_clear_meta_time">Hora de la modificación: %s</string>
<string name="msg_dc_clear_signature_bad">¡Comprobación de firma NO CORRECTA!</string>
<string name="msg_dc_clear_signature_check">Verificando datos de firma</string>
@@ -1055,7 +1038,7 @@
<string name="msg_dc_clear_signature">Guardando datos de firma para más tarde</string>
<string name="msg_dc_clear">Procesando datos de texto no cifrado (`cleartext`)</string>
<string name="msg_dc_error_bad_passphrase">Error desbloqueando clave, ¡contraseña incorrecta!</string>
- <string name="msg_dc_error_sym_passphrase">¡Error al descifrar datos! (¿frase-contraseña errónea?)</string>
+ <string name="msg_dc_error_sym_passphrase">¡Error al descifrar datos! (¿frase-contraseña incorrecta?)</string>
<string name="msg_dc_error_corrupt_data">¡Los datos están corruptos!</string>
<string name="msg_dc_error_extract_key">¡Error desconocido al desbloquear clave!</string>
<string name="msg_dc_error_integrity_check">¡Error de comprobación de integridad!</string>
@@ -1085,13 +1068,11 @@
<string name="msg_dc_insecure_key">Clave no segura: O bien el número de bits de la clave RSA/DSA/ElGamal es demasiado pequeño o la curva/algoritmo ECC es considerado no seguro! Esto puede ocurrir porque la aplicación no esté actualizada, o por un ataque de degradación de versión.</string>
<!--Messages for VerifySignedLiteralData operation-->
<string name="msg_vl">Comenzando comprobación de firma</string>
- <string name="msg_vl_error_no_siglist">No hay lista de firmas en los datos literales firmados</string>
- <string name="msg_vl_error_wrong_key">Mensaje no firmado con una clave correcta</string>
<string name="msg_vl_error_missing_literal">No hay carga útil en los datos literales firmados</string>
- <string name="msg_vl_clear_meta_file">Nombre de fichero: %s</string>
+ <string name="msg_vl_clear_meta_file">Nombre del fichero: %s</string>
<string name="msg_vl_clear_meta_mime">Tipo MIME: %s</string>
<string name="msg_vl_clear_meta_time">Fecha de modificación: %s</string>
- <string name="msg_vl_clear_meta_size">Tamaño de fichero: %s</string>
+ <string name="msg_vl_clear_meta_size">Tamaño del fichero: %s</string>
<string name="msg_vl_clear_signature_check">Verificando datos de firma</string>
<string name="msg_vl_error_integrity_check">¡Error de comprobación de integridad!</string>
<string name="msg_vl_ok">Correcto</string>
@@ -1106,7 +1087,6 @@
<string name="msg_se_success">Operación de firmado/cifrado completada</string>
<!--Messages for PgpSignEncrypt operation-->
<string name="msg_pse_asymmetric">Preparando claves públicas para cifrado</string>
- <string name="msg_pse_clearsign_only">¡El fimado de texto sin cifrar (cleartext) no está soportado!</string>
<string name="msg_pse_compressing">Preparando compresión</string>
<string name="msg_pse_encrypting">Cifrando datos</string>
<string name="msg_pse_error_bad_passphrase">¡Contraseña incorrecta!</string>
@@ -1132,8 +1112,8 @@
<string name="msg_pse_symmetric">Preparando cifrado simétrico</string>
<string name="msg_crt_certifying">Generando certificaciones</string>
<plurals name="msg_crt_certify_uids">
- <item quantity="one">Certificando una identificación de usuario para la clave %2$s</item>
- <item quantity="other">Certificando %1$d identificaciones de usuario para la clave %2$s</item>
+ <item quantity="one">Certificando una identidad de usuario para la clave %2$s</item>
+ <item quantity="other">Certificando %1$d identidades de usuario para la clave %2$s</item>
</plurals>
<plurals name="msg_crt_certify_uats">
<item quantity="one">Certificando un atributo de usuario para la clave %2$s</item>
@@ -1162,38 +1142,15 @@
<string name="msg_import_fetch_error_decode">¡Error al descifrar juego de claves descargado!</string>
<string name="msg_import_fetch_error">¡La clave no se pudo descargar! (¿problemas con la red?)</string>
<string name="msg_import_fetch_keybase">Descargando desde keybase.io: %s</string>
- <string name="msg_import_fetch_error_keyserver">No se pudo obtener clave de los servidores de claves: %s</string>
<string name="msg_import_fetch_keyserver">Descargando desde el servidor de claves: %s</string>
<string name="msg_import_fetch_keyserver_ok">La clave se descargó con éxito</string>
<string name="msg_import_keyserver">Usando el servidor de claves %s</string>
- <string name="msg_import_fingerprint_error">¡La huella de validación de la clave descargada no coincidió con la esperada!</string>
- <string name="msg_import_fingerprint_ok">La comprobación de la huella de validación de clave es Correcta</string>
<string name="msg_import_merge">Incorporando datos descargados</string>
<string name="msg_import_merge_error">¡Error al fusionar datos descargados!</string>
<string name="msg_import_error">¡La operación de importación falló!</string>
<string name="msg_import_error_io">¡Fallo en la operación de importación debido a un error de e/s!</string>
<string name="msg_import_partial">¡Operación de importado completada, con errores!</string>
<string name="msg_import_success">¡Operación de importado exitosa!</string>
- <plurals name="msg_export">
- <item quantity="one">Exportando una clave</item>
- <item quantity="other">Exportando %d claves</item>
- </plurals>
- <string name="msg_export_file_name">Nombre de fichero: %s</string>
- <string name="msg_export_all">Exportando todas las claves</string>
- <string name="msg_export_public">Exportando clave pública %s</string>
- <string name="msg_export_upload_public">Subiendo clave pública %s</string>
- <string name="msg_export_secret">Exportando clave secreta (privada) %s</string>
- <string name="msg_export_error_no_file">¡No se especificó nombre de fichero!</string>
- <string name="msg_export_error_fopen">¡Error al abrir el fichero!</string>
- <string name="msg_export_error_no_uri">¡No se especificó URI!</string>
- <string name="msg_export_error_uri_open">¡Error al abrir URI de flujo de datos (stream)!</string>
- <string name="msg_export_error_storage">¡El almacenamiento no está listo para escritura!</string>
- <string name="msg_export_error_db">¡Error de base de datos!</string>
- <string name="msg_export_error_io">¡Error de entrada/salida!</string>
- <string name="msg_export_error_key">¡Error al preprocesar los datos de la clave!</string>
- <string name="msg_export_error_upload">¡Error al subir clave al servidor! Por favor, compruebe su conexión a Internet</string>
- <string name="msg_export_success">Operación de exportado exitosa</string>
- <string name="msg_export_upload_success">Subida al servidor de claves completada</string>
<string name="msg_del_error_empty">¡No hay nada que borrar!</string>
<string name="msg_del_error_multi_secret">¡Las claves secretas (privadas) sólo se pueden borrar individualmente!</string>
<plurals name="msg_del">
@@ -1216,9 +1173,28 @@
<string name="msg_revoke_key">Revocando clave %s</string>
<string name="msg_revoke_key_fail">Fallo al revocar clave</string>
<string name="msg_revoke_ok">Clave revocada con éxito</string>
+ <!--Linked Identity verification-->
+ <string name="msg_lv">Verificando identidad vinculada...</string>
+ <string name="msg_lv_match">Buscando credencial</string>
+ <string name="msg_lv_match_error">¡No se encontró credencial en el recurso!</string>
+ <string name="msg_lv_fp_ok">Huella de validación de clave correcta.</string>
+ <string name="msg_lv_fp_error">¡La huella de validación de clave no coincide!</string>
+ <string name="msg_lv_error_twitter_auth">¡Error al obtener credencial de autentificación de Twitter!</string>
+ <string name="msg_lv_error_twitter_handle">¡El nombre de usuario de la cuenta de Twitter no coincide en la respuesta!</string>
+ <string name="msg_lv_error_twitter_response">¡Respuesta inesperada desde la API de Twitter!</string>
+ <string name="msg_lv_error_github_handle">¡El nombre de usuario de la cuenta de GitHub no coincide en la respuesta!</string>
+ <string name="msg_lv_error_github_not_found">¡Gist no contiene ficheros coincidentes!</string>
+ <string name="msg_lv_fetch">Descargando URI \'%s\'</string>
+ <string name="msg_lv_fetch_redir">Siguiendo redireccionamiento a \'%s\'</string>
+ <string name="msg_lv_fetch_ok">Se completó la descarga (HTTP %s)</string>
+ <string name="msg_lv_fetch_error">Error del servidor (HTTP %s)</string>
+ <string name="msg_lv_fetch_error_url">¡La URL está mal formada!</string>
+ <string name="msg_lv_fetch_error_io">¡Error de E/S!</string>
+ <string name="msg_lv_fetch_error_format">¡Error de formato!</string>
+ <string name="msg_lv_fetch_error_nothing">¡Recurso no encontrado!</string>
<string name="msg_acc_saved">Cuenta guardada</string>
<string name="msg_download_success">¡Descargado con éxito!</string>
- <string name="msg_download_no_valid_keys">¡No se encontraron claves vigentes en el fichero/portapapeles!</string>
+ <string name="msg_download_no_valid_keys">¡No se encontraron claves válidas en el fichero/portapapeles!</string>
<string name="msg_download_no_pgp_parts">PENDIENTE: ¡plurales!</string>
<plurals name="error_import_non_pgp_part">
<item quantity="one">parte del archivo cargado es un objeto OpenPGP válido pero no una clave OpenPGP</item>
@@ -1230,18 +1206,13 @@
<string name="msg_download_query_failed">Ocurrió un error al buscar claves.</string>
<!--Messages for Keybase Verification operation-->
<string name="msg_keybase_verification">Intentando la verificación con Keybase para %s</string>
- <string name="msg_keybase_error_no_prover">No se encontró prueba verificadora para %s</string>
- <string name="msg_keybase_error_fetching_evidence">Problema al descargar prueba</string>
- <string name="msg_keybase_error_key_mismatch">La huella de validación de la clave no coincide con la prueba publicada</string>
+ <string name="msg_keybase_error_no_prover">No se encontró verificador del comprobante para %s</string>
+ <string name="msg_keybase_error_fetching_evidence">Problema al descargar comprobante</string>
+ <string name="msg_keybase_error_key_mismatch">La huella de validación de la clave no coincide con la del post del comprobante</string>
<string name="msg_keybase_error_dns_fail">Fallo al obtener Registro DNS TXT</string>
<string name="msg_keybase_error_specific">%s</string>
- <string name="msg_keybase_error_msg_payload_mismatch">La prueba descifrada publicada no coincide con el valor esperado</string>
- <!--Messages for Export Log operation-->
- <string name="msg_export_log_start">Exportando registro (log)</string>
- <string name="msg_export_log_error_fopen">Error abriendo fichero</string>
- <string name="msg_export_log_error_no_file">¡No se especificó nombre de fichero!</string>
- <string name="msg_export_log_error_writing">¡Error de E/S al escribir al fichero!</string>
- <string name="msg_export_log_success">¡Registro (log) exportado con éxito!</string>
+ <string name="msg_keybase_error_msg_payload_mismatch">El post del comprobante descifrado no coincide con el valor esperado</string>
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<string name="passp_cache_notif_click_to_clear">Pulsar para limpiar contraseñas.</string>
<plurals name="passp_cache_notif_n_keys">
@@ -1252,7 +1223,7 @@
<string name="passp_cache_notif_clear">Limpiar contraseñas</string>
<string name="passp_cache_notif_pwd">Contraseña</string>
<!--Keyserver sync-->
- <string name="keyserver_sync_orbot_notif_title">La sincronizacion desde la nube requiere Orbot</string>
+ <string name="keyserver_sync_orbot_notif_title">Sincronizar desde los servidores requiere Orbot</string>
<string name="keyserver_sync_orbot_notif_msg">Pulse para iniciar Orbot</string>
<string name="keyserver_sync_orbot_notif_start">Iniciar Orbot</string>
<string name="keyserver_sync_orbot_notif_ignore">Directamente</string>
@@ -1271,14 +1242,12 @@
<!--unsorted-->
<string name="section_certifier_id">Certificador</string>
<string name="section_cert">Detalles del certificado</string>
- <string name="label_user_id">Identificación</string>
- <string name="unknown_uid">&lt;desconocido&gt;</string>
+ <string name="label_user_id">Identidad</string>
+ <string name="unknown_uid"><![CDATA[<unknown>]]></string>
<string name="empty_certs">No hay certificados para esta clave</string>
<string name="certs_text">Aquí sólo se muestran auto-certificados validados y certificados validados creados con sus claves.</string>
<string name="section_uids_to_certify">Identificaciones para</string>
<string name="certify_text">Las claves que está importando contienen \"identidades\": nombres y direcciones de correo electrónico. Para confirmación seleccione exactamente aquellas que coincidan con lo que esperaba.</string>
- <string name="certify_fingerprint_text">Compare la huella de validación de clave mostrada, caracter por caracter, con la que se muestra en el dispositivo de su colega.</string>
- <string name="certify_fingerprint_text2">¿Coinciden las huellas de validación de clave mostradas?</string>
<string name="label_revocation">Razón de la revocación</string>
<string name="label_cert_type">Tipo</string>
<string name="error_key_not_found">¡Clave no encontrada!</string>
@@ -1295,8 +1264,8 @@
<string name="contact_show_key">Mostrar clave (%s)</string>
<string name="swipe_to_update">Gesto de barrido hacia abajo para actualizar desde el servidor de claves</string>
<string name="error_no_file_selected">¡Seleccione al menos un fichero a cifrar!</string>
- <string name="error_multi_files">El guardado de múltiples ficheros no está soportado. Esta es una limitación del actual Android.</string>
- <string name="error_multi_clipboard">El cifrado de múltiples ficheros hacia el portapapeles no está soportado.</string>
+ <string name="error_multi_files">Guardar múltiples ficheros no está soportado. Esta es una limitación del actual Android.</string>
+ <string name="error_multi_clipboard">Cifrar múltiples ficheros hacia el portapapeles no está soportado.</string>
<string name="error_detached_signature">La operación de sólo-firmado de ficheros binarios no está soportada, seleccione al menos una clave de cifrado.</string>
<string name="error_empty_text">¡Escriba algún texto a cifrar!</string>
<string name="key_colon">Clave:</string>
@@ -1338,7 +1307,7 @@
<string name="button_bind_key">Ligar clave</string>
<string name="yubikey_serno">Nº de serie: %s</string>
<string name="yubikey_key_holder">Titular de la clave:</string>
- <string name="yubikey_key_holder_not_set">Titular de la clave: &lt;no establecido&gt;</string>
+ <string name="yubikey_key_holder_not_set"><![CDATA[Titular de la clave: <not set>]]></string>
<string name="yubikey_status_bound">La YubiKey coincide y está ligada a la clave</string>
<string name="yubikey_status_unbound">La YubiKey coincide, puede ligarse a la clave</string>
<string name="yubikey_status_partly">La YubiKey coincide, parcialmente ligada a la clave</string>
@@ -1362,7 +1331,6 @@
<string name="error_nfc_header">La YubiKey informó de un byte %s no válido.</string>
<string name="error_nfc_tag_lost">La YubiKey ha sido retirada demasiado pronto. Mantenga la YubiKey en el reverso hasta que la operación finalice.</string>
<string name="error_nfc_try_again">Intentar de nuevo</string>
- <string name="error_pin_nodefault">¡El PIN por defecto fue rechazado!</string>
<string name="error_temp_file">Error al crear fichero temporal.</string>
<string name="btn_delete_original">Borrar fichero original</string>
<string name="snack_encrypt_filenames_on">Los nombres de fichero <b>están</b> cifrados.</string>
@@ -1374,8 +1342,8 @@
<string name="error_loading_keys">¡Error al cargar claves!</string>
<string name="error_empty_log">(error, registro (log) vacío)</string>
<string name="error_reading_text">¡No se pudo leer entrada a descifrar!</string>
- <string name="filename_unknown">&lt;sin nombre de fichero&gt;</string>
- <string name="filename_unknown_text">&lt;datos en texto sin cifrar&gt;</string>
+ <string name="filename_unknown">Nombre de fichero desconocido (clic para abrir)</string>
+ <string name="filename_unknown_text">Texto (clic para abrir)</string>
<string name="intent_show">Mostrar contenido firmado/cifrado</string>
<string name="view_internal">Ver en OpenKeychain</string>
<string name="error_preparing_data">¡Error al preparar datos!</string>
@@ -1384,11 +1352,68 @@
<string name="error_saving_file">¡Error al guardar fichero!</string>
<string name="file_saved">¡Fichero guardado!</string>
<string name="file_delete_ok">Fichero original borrado.</string>
- <string name="file_delete_none">¡No se borró ningún fichero! (¿ya se había borrado?)</string>
+ <string name="file_delete_none">¡No se borró ningún fichero! (¿se había borrado ya?)</string>
<string name="file_delete_exception">¡No se pudo borrar el fichero original!</string>
<string name="error_clipboard_empty">¡Portapapeles vacío!</string>
<string name="error_clipboard_copy">¡Error al copiar datos al portapapeles!</string>
<string name="error_scan_fp">¡Error al escanear huella de validación de clave!</string>
<string name="error_scan_match">¡Las huellas de validación de clave no coinciden!</string>
<string name="error_expiry_past">¡La fecha de caducidad es del pasado!</string>
+ <string name="linked_create_https_1_1">Al crear una identidad vinculada de este tipo, puede vincular su clave a un sitio web que controle.</string>
+ <string name="linked_create_https_1_2">Para hacer esto, publique un fichero de texto en ese sitio web, y luego cree una identidad vinculada que enlace a ella.</string>
+ <string name="linked_create_https_1_3">Introduzca una URL donde pueda situar un fichero de texto como comprobante. ¡Tenga en cuenta que su servidor soporta HTTPS y tiene un certificado TLS válido!</string>
+ <string name="linked_create_https_1_4">Ejemplo: https://example.com/pgpkey.txt</string>
+ <string name="linked_create_https_created">El fichero comprobante ha sido creado. Para el siguiente paso, debe guardarlo y subirlo a la URI que indicó:</string>
+ <string name="linked_create_https_2_1">Se ha creado un fichero comprobante para esta URI:</string>
+ <string name="linked_create_https_2_2">Para el siguiente paso, debe guardar y subir este fichero.</string>
+ <string name="linked_create_https_2_3">Asegúrese de que el fichero es accesible en la URI correcta, y luego verifique su configuración.</string>
+ <string name="linked_create_https_2_4">Tras una verificación exitosa, pulse el botón Finalizar para añadir la identidad vinculada a su juego de claves y finalizar el proceso.</string>
+ <string name="linked_create_twitter_1_1">Al crear una identidad vinculada de este tipo, puede vincular su clave a una cuenta de Twitter que controle.</string>
+ <string name="linked_create_twitter_1_2">Para hacer esto, publique un twit específico en su línea de tiempo, y luego cree una identidad vinculada que enlace a este twit.</string>
+ <string name="linked_create_twitter_1_3">Introduzca el nombre en pantalla de su Twitter para continuar.</string>
+ <string name="linked_create_twitter_handle">Nombre de usuario de Twitter</string>
+ <string name="linked_create_twitter_2_1">¡Haga clic en cualquiera de los botones para twitear el mensaje!</string>
+ <string name="linked_create_twitter_2_2">Puede editar el twit antes de publicarlo, en tanto no modifique el texto dentro de los corchetes.</string>
+ <string name="linked_create_twitter_2_3">Una vez su twit se haya publicado como &lt;b&gt;@%s&lt;/b&gt;, haga clic en el botón Verificar para escanear su línea de tiempo en su busca.</string>
+ <string name="linked_create_twitter_2_4">Tras una verificación exitosa, pulse el botón Finalizar para añadir la identidad vinculada a su juego de claves y finalizar el proceso.</string>
+ <string name="linked_create_verify">Verificar</string>
+ <string name="linked_text_clipboard">El texto ha sido copiado al portapapeles</string>
+ <string name="linked_verified_https">El vínculo entre este sitio web y la clave fue verificado con seguridad. <b>Si cree que el sitio web es genuino</b>, confirme esta verificación con su clave.</string>
+ <string name="linked_verified_github">El vínculo entre esta cuenta de GitHub y la clave fue verficado con seguridad. <b>Si cree que la cuenta es genuina</b>, confirme esta verificación con su clave.</string>
+ <string name="linked_verified_dns">El vínculo entre este nombre de dominio y la clave fue verificado con seguridad. <b>Si cree que el dominio es genuino</b>, confirme esta verificación con su clave.</string>
+ <string name="linked_verified_twitter">El vínculo entre esta cuenta de Twitter y la clave fue verificado con seguridad. <b>Si cree que la cuenta es genuina</b>, confirme esta verificación con su clave.</string>
+ <string name="linked_verified_secret_https">Todo parece en orden.</string>
+ <string name="linked_verified_secret_github">Todo parece en orden.</string>
+ <string name="linked_verified_secret_dns">Todo parece en orden.</string>
+ <string name="linked_verified_secret_twitter">Todo parece en orden.</string>
+ <plurals name="linked_id_expand">
+ <item quantity="one">Hay un tipo de identidad desconocida más</item>
+ <item quantity="other">Hay %d tipos de identidad desconocida más</item>
+ </plurals>
+ <!--Other Linked Identity strings-->
+ <string name="linked_select_2">Seleccione un tipo:</string>
+ <string name="linked_id_generic_text">Este fichero afirma ser propiedad de la clave OpenPGP con identidad larga %2$s.\n\nCredencial para comprobación:\n%1$s</string>
+ <string name="linked_id_github_text">Este Gist confirma la identidad vinculada en mi clave OpenPGP, y la vincula a esta cuenta de GitHub.\n\nCredencial para comprobación:\n%1$s</string>
+ <string name="linked_verifying">Verificando...</string>
+ <string name="linked_verify_success">¡Verificado!</string>
+ <string name="linked_verify_error">¡Error de verificación!</string>
+ <string name="linked_verify_pending">Aún no verificado</string>
+ <string name="linked_need_verify">¡El recurso tiene que ser verificado antes de que pueda continuar!</string>
+ <string name="menu_linked_add_identity">Vincular a cuenta.</string>
+ <string name="section_linked_identities">Identidades enlazadas</string>
+ <string name="btn_finish">Finalizar</string>
+ <string name="linked_title_https">Sitio web (HTTPS)</string>
+ <string name="linked_title_dns">Nombre de dominio (DNS)</string>
+ <string name="linked_title_github">GitHub</string>
+ <string name="linked_title_twitter">Twitter</string>
+ <string name="card_linked_identity">Identidad vinculada</string>
+ <string name="linked_button_verify">Verificar</string>
+ <string name="linked_button_retry">Reintentar</string>
+ <string name="linked_button_confirm">Confirmar</string>
+ <string name="linked_button_view">Ver</string>
+ <string name="linked_text_verifying">Verificando...</string>
+ <string name="linked_text_error">Error</string>
+ <string name="linked_text_confirming">Confirmando...</string>
+ <string name="linked_ids_more_unknown">%d tipos de identidad desconocida más</string>
+ <string name="title_linked_id_create">Crear identidad vinculada</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-eu/strings.xml b/OpenKeychain/src/main/res/values-eu/strings.xml
index de4fb68d6..b81f7364f 100644
--- a/OpenKeychain/src/main/res/values-eu/strings.xml
+++ b/OpenKeychain/src/main/res/values-eu/strings.xml
@@ -9,6 +9,7 @@
<string name="title_decrypt">Dekriptatu</string>
<string name="title_add_subkey">Gehitu azpigiltza</string>
<string name="title_edit_key">Editatu Giltza</string>
+ <string name="title_linked_create">Sortu Loturatutako Nortasuna</string>
<string name="title_preferences">Ezarpenak</string>
<string name="title_api_registered_apps">Aplikazioak</string>
<string name="title_key_server_preference">OpenPGP giltza-zerbitzariak</string>
@@ -31,7 +32,6 @@
<string name="title_exchange_keys">Trukatu Giltzak</string>
<string name="title_advanced_key_info">Argibide Hedatuak</string>
<string name="title_delete_secret_key">Ezabatu ZURE \'%s\' giltza?</string>
- <string name="title_export_log">Esportatu Oharra</string>
<string name="title_manage_my_keys">Kudeatu nire giltzak</string>
<!--section-->
<string name="section_user_ids">Nortasunak</string>
@@ -39,12 +39,17 @@
<string name="section_linked_system_contact">Loturatutako Sistema Harremana</string>
<string name="section_should_you_trust">Fidatu behar zara giltza honetaz?</string>
<string name="section_proof_details">Probatu egiaztapena</string>
- <string name="section_cloud_evidence">Hodeiko probak</string>
<string name="section_keys">Azpigiltzak</string>
- <string name="section_cloud_search">Hodei bilaketa</string>
- <string name="section_passphrase_cache">Sarhitz/PIN Kudeaketa</string>
- <string name="section_proxy_settings">Proxy Ezarpenak</string>
+ <string name="section_cloud_search">Giltza Bilaketa</string>
+ <string name="section_cloud_search_summary">Giltza-zerbitzaria, keybase.io</string>
+ <string name="section_passphrase_cache">Sarhitzak eta PIN-ak</string>
+ <string name="section_passphrase_cache_summary">Kudeaketa, erabiltzaile interfazea, gogoratu ordua</string>
+ <string name="section_proxy_settings">Sare Izengabetasuna</string>
+ <string name="section_proxy_settings_summary">Tor, Proxy Ezarpenak</string>
<string name="section_gui">Interfazea</string>
+ <string name="section_sync_settings">Aldiberetzea</string>
+ <string name="section_sync_settings_summary">Berezgaitasunezko giltzaeguneraketa, harreman lotura</string>
+ <string name="section_experimental_features">Ezaugarri Esperimentalak</string>
<string name="section_certify">Baieztatu</string>
<string name="section_actions">Ekintzak</string>
<string name="section_share_key">Giltza</string>
@@ -70,12 +75,11 @@
<string name="btn_back">Atzera</string>
<string name="btn_no">Ez</string>
<string name="btn_match">Hatz-aztarnak bat datoz</string>
- <string name="btn_share_encrypted_signed">Enkriptatu eta elkarbanatu idazkia</string>
- <string name="btn_copy_encrypted_signed">Enkriptatu eta kopiatu idazkia</string>
+ <string name="btn_share_encrypted_signed">Enkriptatu/sinatu eta elkarbanatu idazkia</string>
+ <string name="btn_copy_encrypted_signed">Enkriptatu/sinatu eta kopiatu idazkia</string>
<string name="btn_view_cert_key">Ikusi egiaztagiri giltza</string>
<string name="btn_create_key">Sortu giltza</string>
<string name="btn_add_files">Gehitu agiria(k)</string>
- <string name="btn_share_decrypted_text">Elkarbanatu dekriptaturiko idazkia</string>
<string name="btn_copy_decrypted_text">Kopiatu dekriptaturiko idazkia</string>
<string name="btn_decrypt_clipboard">Irakurri gakotik</string>
<string name="btn_decrypt_files">Hautatu sarrera agiria</string>
@@ -89,7 +93,6 @@
<!--menu-->
<string name="menu_preferences">Ezarpenak</string>
<string name="menu_help">Laguntza</string>
- <string name="menu_export_key">Babeskopiatu Agirira</string>
<string name="menu_delete_key">Ezabatu giltza</string>
<string name="menu_manage_keys">Kudeatu nire giltzak</string>
<string name="menu_search">Bilatu</string>
@@ -100,8 +103,7 @@
<string name="menu_export_all_keys">Esportatu giltza guztiak</string>
<string name="menu_update_all_keys">Eguneratu giltza guztiak</string>
<string name="menu_advanced">Argibide Hedatuak</string>
- <string name="menu_certify_fingerprint">Baieztatu hatz-aztarna alderaketa bidez</string>
- <string name="menu_export_log">Esportatu Oharra</string>
+ <string name="menu_certify_fingerprint">Egiaztatu hatz-aztarna bidez</string>
<string name="menu_keyserver_add">Gehitu</string>
<!--label-->
<string name="label_message">Idazkia</string>
@@ -118,9 +120,7 @@
<string name="label_file_ascii_armor">Gaitu ASCII Armor</string>
<string name="label_write_version_header">Jakinarazi besteei OpenKeychain erabiltzen ari zarela</string>
<string name="label_write_version_header_summary">\'OpenKeychain v2.7\' idazten du OpenPGP sinadura, idazkia zifratzen du eta giltzak esportatzen ditu</string>
- <string name="label_use_default_yubikey_pin">Erabili berezko YubiKey PIN-a</string>
<string name="label_use_num_keypad_for_yubikey_pin">Erabili zenbaki teklatua YubiKey PIN-erako</string>
- <string name="label_label_use_default_yubikey_pin_summary">Berezko PIN (123456) erabiltzen du NFC bidezko YubiKeys sarbiderako </string>
<string name="label_asymmetric_from">Hasi saioa honekin:</string>
<string name="label_to">Enkriptatu hona:</string>
<string name="label_delete_after_encryption">Ezabatu agiriak enkriptatu ondoren</string>
@@ -144,7 +144,7 @@
<string name="label_name">Izena</string>
<string name="label_comment">Aipamena</string>
<string name="label_email">Post@</string>
- <string name="label_send_key">Aldiberetu hodeiarekin</string>
+ <string name="label_send_key">Aldiberetu Internet-ekin</string>
<string name="label_fingerprint">Hatz-aztarna</string>
<string name="expiry_date_dialog_title">Ezarri epemuga eguna</string>
<string name="label_keyservers_title">Giltza-zerbitzariak</string>
@@ -154,15 +154,25 @@
<string name="label_enable_compression">Gaitu konpresioa</string>
<string name="label_encrypt_filenames">Enkriptatu agirizenak</string>
<string name="label_hidden_recipients">Ezkutatu jasotzaileak</string>
- <string name="label_verify_keyserver">Egiaztatu giltza-zerbitzaria</string>
- <string name="label_enter_keyserver_url">Sartu giltza-zerbitzariaren URL-a</string>
<string name="label_keyserver_dialog_delete">Ezabatu giltza-zerbitzaria</string>
<string name="label_theme">Azalgaia</string>
<string name="pref_keyserver">OpenPGP giltza-zerbitzariak</string>
<string name="pref_keyserver_summary">Bilatu giltzak hautaturiko OpenPGP giltza-zerbitzarietan (HKP protokoloa)</string>
<string name="pref_keybase">keybase.io</string>
<string name="pref_keybase_summary">Bilatu giltzak keybase.io-an</string>
+ <string name="label_sync_settings_keyserver_title">Berezgaitasunez eguneratu giltzak</string>
+ <string name="label_sync_settings_keyserver_summary_on">Astebete baino zaharragoak diren giltzak hobetsitasko giltza-zerbitzaritik eguneraten dira</string>
+ <string name="label_sync_settings_keyserver_summary_off">Berezgaitasunez eguneratzen ez diren giltzak</string>
+ <string name="label_sync_settings_contacts_title">Lotu giltzak harremanekin</string>
+ <string name="label_sync_settings_contacts_summary_on">Lotu giltzak harremanekin izen eta post@ helbideetan ohinarrituz. Hau erabat lineaz-kanpo gertatzen da zure gailuan.</string>
+ <string name="label_sync_settings_contacts_summary_off">Giltza berriak ez dira harremanekin lotuko</string>
<!--label shown in Android settings under the OpenKeychain account-->
+ <string name="keyserver_sync_settings_title">Berezgaitasunez eguneratu giltzak</string>
+ <string name="label_experimental_settings_desc_title">Kontuz</string>
+ <string name="label_experimental_settings_desc_summary">Ezaugarri hauek ez dute amaitu edo erabiltzaile jarduera/segurtasun emaitzak erdietsita. Honela, ez dira beren segurtasunean ohinarritzen eta mesedez ez jakinarazi aurkitzen dituzun arazoak!</string>
+ <string name="label_experimental_settings_linked_identities_title">Lotutako Nortasunak</string>
+ <string name="label_experimental_settings_linked_identities_summary">Lotu giltzak Twitter, GitHub, webgune edo DNS-ra (keybase.io antzekoa baina zentralizatu gabea)</string>
+ <string name="label_experimental_settings_theme_summary">(Ikurrak eta ikusleiho asko oraindik ez daude azalgai ilunarekin zehaztuta)</string>
<!--Proxy Preferences-->
<string name="pref_proxy_tor_title">Gaitu Tor</string>
<string name="pref_proxy_tor_summary">Orbot ezarrita egotea behar du</string>
@@ -176,22 +186,18 @@
<string name="pref_proxy_type_choice_http">HTTP</string>
<string name="pref_proxy_type_choice_socks">SOCKS</string>
<!--OrbotHelper strings-->
- <string name="orbot_ignore_tor">Ez erabili Tor</string>
<!--InstallDialogFragment strings-->
<string name="orbot_install_dialog_title">Ezarri Orbot edo erabili Tor?</string>
<string name="orbot_install_dialog_install">Ezarri</string>
<string name="orbot_install_dialog_content">Orbot ezarrita eta proxy trafiko igaropena gaituta eduki behar duzu. Nahi duzu ezartzea?</string>
<string name="orbot_install_dialog_cancel">Ezeztatu</string>
- <string name="orbot_install_dialog_ignore_tor">Ez erabili Tor</string>
<!--StartOrbotDialogFragment strings-->
<string name="orbot_start_dialog_title">Abiarazi Orbot?</string>
- <string name="orbot_start_dialog_content">Ez dirudi Orbot ekinean dagoenik. Nahi duzu abiaraztea eta Tor-era elkartzea?</string>
<string name="orbot_start_btn">Abiarazi Orbot</string>
<string name="orbot_start_dialog_start">Abiarazi Orbot</string>
<string name="orbot_start_dialog_cancel">Ezeztatu</string>
- <string name="orbot_start_dialog_ignore_tor">Ez erabili Tor</string>
- <string name="user_id_no_name">&lt;izen gabe&gt;</string>
- <string name="none">&lt;ezer ez&gt;</string>
+ <string name="user_id_no_name"><![CDATA[<izengabe>]]></string>
+ <string name="none"><![CDATA[<ezer ez>]]></string>
<plurals name="n_keys">
<item quantity="one">1 giltza</item>
<item quantity="other">%d giltza</item>
@@ -215,6 +221,7 @@
<string name="choice_4hours">4 ordu</string>
<string name="choice_8hours">8 ordu</string>
<string name="choice_forever">betirako</string>
+ <string name="choice_select_cert">Hautatu Giltza bat</string>
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
@@ -235,7 +242,6 @@
<string name="no_filemanager_installed">Ez dago agiri kudeatzaile bateragarririk ezarrita.</string>
<string name="passphrases_do_not_match">Sarhitzak ez datoz bat.</string>
<string name="passphrase_must_not_be_empty">Mesedez sartu sarhitz bat.</string>
- <string name="passphrase_for_symmetric_encryption">Enkriptaketa simetrikoa.</string>
<string name="passphrase_for">Sartu \'%s\'-rako sarhitza</string>
<string name="pin_for">Sartu PIN-a \'%s\'-rako</string>
<string name="yubikey_pin_for">Sartu PIN-a YubKey-ra sartzeko \'%s\'-rentzat</string>
@@ -258,7 +264,6 @@
<string name="specify_backup_dest_secret_single">Zure giltzaren babeskopia oso bat egingo da, mesedez adierazi helmuga agiria.\nKONTUZ: Agiria gainidatzi egingo da egonez gero!</string>
<string name="specify_backup_dest_secret">Giltza guztien, zeureak barne, babeskopia oso bat egingo da, mesedez adierazi helmuga agiriak.\nKONTUZ: Agiria gainidatzi egingo da egonez gero!</string>
<string name="key_deletion_confirmation_multi">Egitan nahi duzu hautaturiko giltzak ezabatzea?</string>
- <string name="secret_key_deletion_confirmation">Ezabatu ondoren ezingo dituzu giltza honekin enkriptatutako mezuak irakurri eta berarekin egindako giltza baieztapen guztiak galduko dira!</string>
<string name="public_key_deletetion_confirmation">Ezabatu \'%s\' giltza?</string>
<string name="also_export_secret_keys">Esportatu giltza sekretuak ere</string>
<string name="reinstall_openkeychain">Akats ezagun bat aurkitu duzu Android-rekin. Mesedez ezarri berriro OpenKeychain zure harremanak giltzekin lotzea nahi badituzu.</string>
@@ -267,7 +272,6 @@
<string name="no_keys_exported">Ez da giltzarik esportatu.</string>
<string name="key_creation_el_gamal_info">Oharra: azpigiltzek bakarrik sostengatzen dute EIGamal.</string>
<string name="key_not_found">Ezin da %08X giltza aurkitu.</string>
- <string name="specify_file_to_export_log_to">Mesedez adierazi zein agirira esportatu. \nKONTUZ: Agiria gainidatzi egingo da egonez gero.</string>
<plurals name="bad_keys_encountered">
<item quantity="one">%d giltza sekretu gaitz ezikusita. Badaiteke esportatu izana\n --export-secret-subkeys aukerarekin.\nZihurtatu esportatzen duzula --export-secret-keys aukerarekin ordez.</item>
<item quantity="other">%d giltza sekretu gaitz ezikusita. Badaiteke esportatu izana\n --export-secret-subkeys aukerarekin.\nZihurtatu esportatzen duzula --export-secret-keys aukerarekin ordez.</item>
@@ -277,7 +281,6 @@
<string name="key_copied_to_clipboard">Giltza gakora kopiatu da!</string>
<string name="fingerprint_copied_to_clipboard">Hatz-aztarna gakora kopiatu da!</string>
<string name="select_key_to_certify">Mesedez hautatu baiztapenerako erabiltzeko giltza!</string>
- <string name="key_too_big_for_sharing">Giltza handiegia da modu honetan elkarbanatzeko!</string>
<string name="text_copied_to_clipboard">Idazkia gakora kopiatu da!</string>
<!--errors
no punctuation, all lowercase,
@@ -363,8 +366,8 @@
<string name="progress_encrypting">datuak enkriptatzen...</string>
<string name="progress_decrypting">datuak dekriptatzen...</string>
<string name="progress_preparing_signature">sinadura gertatzen...</string>
- <string name="progress_generating_signature">sinadura sortzen...</string>
<string name="progress_processing_signature">sinadura prozesatzen...</string>
+ <string name="progress_generating_signature">sinadura sortzen...</string>
<string name="progress_verifying_signature">sinadura egiaztatzen...</string>
<string name="progress_signing">sinatzen...</string>
<string name="progress_certifying">egiaztagiritzen...</string>
@@ -376,15 +379,10 @@
<string name="progress_deleting">giltzak ezabatzen...</string>
<string name="progress_con_saving">sendotu: katxean gordetzen...</string>
<string name="progress_con_reimport">sendotu: berrinportatzen...</string>
- <string name="progress_verifying_keyserver_url">giltza-zerbitzaria egiaztatzen...</string>
<string name="progress_starting_orbot">Orbot Abiarazten...</string>
<!--action strings-->
<string name="hint_cloud_search_hint">Bilatu Izena, Post@... bidez</string>
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -414,7 +412,7 @@
<string name="help_about_version">Bertsioa:</string>
<!--Import-->
<string name="import_tab_keyserver">Giltza-zerbitzaria</string>
- <string name="import_tab_cloud">Hodei Bilaketa</string>
+ <string name="import_tab_cloud">Giltza Bilaketa</string>
<string name="import_tab_direct">Agiria/Gakoa</string>
<string name="import_tab_qr_code">QR Kodea/NFC</string>
<string name="import_import">Inportatu hautaturiko giltzak</string>
@@ -431,11 +429,11 @@
<string name="with_cancelled">, ezeztatu arte</string>
<!--Import result toast-->
<plurals name="import_keys_added_and_updated_1">
- <item quantity="one">Ongi inportatuta 1 giltza</item>
+ <item quantity="one">Giltza bat ongi inportatuta</item>
<item quantity="other">Ongi inportatuta %1$d giltza</item>
</plurals>
<plurals name="import_keys_added_and_updated_2">
- <item quantity="one">eta eguneratuta giltza%2$s.</item>
+ <item quantity="one">eta eguneratuta giltza bat%2$s.</item>
<item quantity="other">eta eguneratuta %1$d giltza%2$s.</item>
</plurals>
<plurals name="import_keys_added">
@@ -482,8 +480,8 @@
<string name="revoke_cancelled">Ukatze eragiketa ezeztatuta.</string>
<!--Certify result toast-->
<plurals name="certify_keys_ok">
- <item quantity="one">Ongi egiaztatuta giltza%2$s.</item>
- <item quantity="other">Ongi egiaztatuta %1$d giltza%2$s.</item>
+ <item quantity="one">Ongi baieztatuta %2$s giltza.</item>
+ <item quantity="other">Ongi baieztatuta %1$d giltza%2$s.</item>
</plurals>
<plurals name="certify_keys_with_errors">
<item quantity="one">Egiaztagiritze hutsegitea!</item>
@@ -542,6 +540,8 @@
<string name="retry_up_dialog_btn_reupload">Bersaiatu Eragiketa</string>
<string name="retry_up_dialog_btn_cancel">Ezeztatu Eragiketa</string>
<!--Delete or revoke private key dialog-->
+ <string name="del_rev_dialog_message">Ez baduzu giltza hau gehiago erabiltzerik nahi, ukatu eta igo egin behar da. Hautatu \'EZABATU BAKARRIK\' giltza OpenKeychain-etik kendu baina beste nonbait erabiltzea nahi baduzu.</string>
+ <string name="del_rev_dialog_title">Ukatu/Ezabatu \'%s\' giltza</string>
<string name="del_rev_dialog_btn_revoke">Ukatu eta igo</string>
<string name="del_rev_dialog_btn_delete">Ezabatu bakarrik</string>
<!--Delete Or Revoke Dialog spinner-->
@@ -554,7 +554,10 @@
</plurals>
<string name="key_list_empty_text1">Ez da giltzarik aurkitu!</string>
<string name="key_list_filter_show_all">Erakutsi giltza guztiak</string>
- <string name="key_list_filter_show_certified">Erakutsi egiaztaturiko giltzak bakarrik</string>
+ <string name="key_list_filter_show_certified">Erakutsi baieztatutako giltzak bakarrik</string>
+ <string name="key_list_fab_qr_code">Eskaneatu QR Kodea</string>
+ <string name="key_list_fab_search">Giltza Bilaketa</string>
+ <string name="key_list_fab_import">Inportatu Agiritik</string>
<!--Key view-->
<string name="key_view_action_edit">Editatu giltza</string>
<string name="key_view_action_encrypt">Enkriptatu idazkia</string>
@@ -571,23 +574,15 @@
<string name="key_view_tab_keybase">Keybase.io</string>
<string name="user_id_info_revoked_title">Ukatuta</string>
<string name="user_id_info_revoked_text">Nortasun hau ukatua izan da giltzaren jabeagaitik. Aurrerantzean ez da baliozkoa.</string>
- <string name="user_id_info_certified_title">Egiaztatuta</string>
- <string name="user_id_info_certified_text">Nortasun hau zeuk egiaztatua da.</string>
- <string name="user_id_info_uncertified_title">Egiaztatu gabea</string>
- <string name="user_id_info_uncertified_text">Nortasun hau ez da egiaztagiritua izan oraindik. Ezin zara zihur egon nortasuna egitan dagokion adierazitako norbanakoari.</string>
+ <string name="user_id_info_certified_title">Baieztatuta</string>
+ <string name="user_id_info_certified_text">Nortasun hau zuek baieztatua da.</string>
+ <string name="user_id_info_uncertified_title">Baieztatu gabea</string>
+ <string name="user_id_info_uncertified_text">Giltza hau oraindik ez da baieztatu. Ezin zara zihur egon giltza egitan norbanako zehatz batena den.</string>
<string name="user_id_info_invalid_title">Baliogabea</string>
<string name="user_id_info_invalid_text">Zerbait oker dago nortasun honekin!</string>
<!--Key trust-->
- <string name="key_trust_already_verified">Giltza hau jadanik baieztatuta duzu!</string>
- <string name="key_trust_it_is_yours">Hau zure giltzetako bat da!</string>
- <string name="key_trust_maybe">Giltza hau ukatua edo iraungitua dago.\nEzin duzu baieztatuta, baina fidatzea hautatu dezakezu.</string>
- <string name="key_trust_revoked">Nortasun hau ukatua izan da giltzaren jabeagaitik. Ez zara berataz fidatu behar.</string>
- <string name="key_trust_expired">Giltza hau iraungituta dago. Ez zara berataz fidatu behar.</string>
- <string name="key_trust_old_keys">Ongi egon daiteke hau erabiltzea giltza hau baliozkoa zen garaiko mezu zahar bat dekriptatzeko.</string>
- <string name="key_trust_no_cloud_evidence">Ez dago hodeiko probarik giltza honen fidagarritasunerako.</string>
<string name="key_trust_start_cloud_search">Hasi bilaketa</string>
<string name="key_trust_results_prefix">Keybase.io \"probak\" eskaintzen ditu giltza honen jabea baieztatzeko:</string>
- <string name="key_trust_header_text">Oharra: Keybase.io egiaztapenak OpenKeychain-en ezaugarri esperimental bat da. QR kodeak eskaneatzea edo giltzak NFC bidez aldatzea gomendatzen dizugu hauek baieztatu ahal izateko.</string>
<!--keybase proof stuff-->
<string name="keybase_narrative_twitter">Argitaratu Twitter-en honela %s</string>
<string name="keybase_narrative_github">GitHub-en %s bezala ezagutzen da</string>
@@ -641,7 +636,7 @@
<string name="edit_key_error_bad_nfc_algo">Txartel adimentsuak ez du algoritmoa sostengatzen!</string>
<string name="edit_key_error_bad_nfc_size">Txartel adimentsuak ez du giltzaren neurria sostengatzen!</string>
<!--Create key-->
- <string name="create_key_upload">Aldiberetu hodeiarekin</string>
+ <string name="create_key_upload">Aldiberetu Internetekin</string>
<string name="create_key_empty">Eremu hau beharrezkoa da</string>
<string name="create_key_passphrases_not_equal">Sarhitzak ez datoz bat</string>
<string name="create_key_final_text">Hurrengo nortasuna sartu duzu:</string>
@@ -657,12 +652,9 @@
<string name="create_key_add_email_text">Post@ helbide gehigarriak ere giltza honekin elkartzen dira eta komunikazio segururako erabili daitezke.</string>
<string name="create_key_email_already_exists_text">Post@ helbidea jadanik gehituta dago</string>
<string name="create_key_email_invalid_email">Post@ heuskarria baliogabea da</string>
- <string name="create_key_yubi_key_pin_text">Mesedez gogoratu PIN-a, beharrezkoa da gero zure YubiKey erabiltzeko. Mesedez idatzi behean Administrari PIN-a eta biltegiratu toki seguru batean.</string>
<string name="create_key_yubi_key_pin">PIN-a</string>
<string name="create_key_yubi_key_admin_pin">Administrari PIN-a</string>
- <string name="create_key_yubi_key_pin_repeat_text">Mesedez sartu PIN-a eta Administrari PIN-a jarraitzeko.</string>
<string name="create_key_yubi_key_pin_repeat">Berridatzi PIN-a</string>
- <string name="create_key_yubi_key_admin_pin_repeat">Berridatzi Administrari PIN-a</string>
<string name="create_key_yubi_key_pin_not_correct">PIN-a ez da zuzena!</string>
<!--View key-->
<string name="view_key_revoked">Ukatuta: Giltza ezin da gehiago erabili!</string>
@@ -675,10 +667,9 @@
<!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Gehitu giltza-zerbitzaria</string>
<string name="edit_keyserver_dialog_title">Editatu giltza-zerbitzaria</string>
- <string name="add_keyserver_verified">Giltza-zerbitzaria egiaztatuta!</string>
<string name="add_keyserver_without_verification">Giltza-zerbitzaria gehituta egiaztapen gabe.</string>
<string name="add_keyserver_invalid_url">URL baliogabea!</string>
- <string name="add_keyserver_connection_failed">Hutsegitea giltza-zerbitzariarekin elkartzerakoan. Mesedez egiaztatu URL-a eta zure internet elkarketa.</string>
+ <string name="add_keyserver_connection_failed">Hutsegitea giltza-zerbitzarira elkartzean! Mesedez egiaztatu zure Internet elkarketa.</string>
<string name="keyserver_preference_deleted">%s ezabatuta</string>
<string name="keyserver_preference_cannot_delete_last">Ezin da azken giltza-zerbitzaria ezabatu. Gutxienez bat behar da!</string>
<!--Navigation Drawer-->
@@ -688,7 +679,6 @@
<string name="drawer_open">Ireki nabigazio marraztzailea</string>
<string name="drawer_close">Itxi nabigazio marraztzailea</string>
<string name="my_keys">Nire Giltzak</string>
- <string name="nav_backup">Babeskopia</string>
<!--hints-->
<string name="encrypt_content_edit_text_hint">Idatzi idazkia</string>
<!--certs-->
@@ -736,7 +726,6 @@
<string name="msg_ip_master_flags_xxxa">Maisu ikurrak: egiaztatu</string>
<string name="msg_ip_master_flags_xxxx">Maisu ikurrak: ezer ez</string>
<string name="msg_ip_merge_public">Inportatutako datuak dagoen giltza-uztai publikoan batzen</string>
- <string name="msg_ip_merge_secret">Inportatutako datuak dagoen giltza-uztai publikoan batzen</string>
<string name="msg_ip_subkey">%s azpigiltza prozesatzen</string>
<string name="msg_ip_subkey_expired">Azpigiltza iraungipena: %s</string>
<string name="msg_ip_subkey_expires">Azpigiltza iraungipena: %s</string>
@@ -802,7 +791,6 @@
<string name="msg_is_importing_subkeys">Azpigiltza sekretuak prozesatzen</string>
<string name="msg_is_error_io_exc">Akatsa giltza-uztaia kodeatzerakoan</string>
<string name="msg_is_merge_public">Inportatutako datuak dagoen giltza-uztai publikoan batzen</string>
- <string name="msg_is_merge_secret">Inportatutako datuak dagoen giltza-uztai publikoan batzen</string>
<string name="msg_is_pubring_generate">Giltza-uztai publikoa sortzen giltza-uztai sekreturako</string>
<string name="msg_is_subkey_nonexistent">%s azpigiltza eskuraezina da giltza sekretuan</string>
<string name="msg_is_subkey_ok">%s azpigiltza eskuragarria bezala markatuta</string>
@@ -850,7 +838,6 @@
<string name="msg_cr_error_no_user_id">Giltza-uztaiak gutxienez erabiltzaile ID batekin sortu behar dira!</string>
<string name="msg_cr_error_no_certify">Maisu giltzak egiaztagiri ikurra izan behar du!</string>
<string name="msg_cr_error_null_expiry">Epemuga ezin daiteke giltza sortzea baino \'lehenago\' izan. Hau programazio akats bat da, mesedez agiritu akats jakinarazpen bat!</string>
- <string name="msg_cr_error_keysize_512">Giltza neurria 512 edo handiagoa izan behar da!</string>
<string name="msg_cr_error_no_curve">Ez da giltzaren neurria adierazi! Hau programazio akats bat da, mesedez agiritu akats jakinarazpen bat!</string>
<string name="msg_cr_error_internal_pgp">Barneko OpenPGP akatsa!</string>
<string name="msg_cr_error_unknown_algo">Algoritmo ezezaguna hautatu da! Hau programazio akats bat da, mesedez agiritu akats jakinarazpen bat!</string>
@@ -995,7 +982,6 @@
<string name="msg_dc_insecure_key">Segurtasun gabeko giltza: Bietako bat, edo RSA/DSA/ElGamal bit luzera laburregia da edo ECC bihurgune/algoritmoa segurtasun gabekotzat hartzen da! Hau aplikazioa eguneratu gabe dagoelako, edo eraso bategaitik gertatu daiteke.</string>
<!--Messages for VerifySignedLiteralData operation-->
<string name="msg_vl">Sinadura egiaztapena abiatzen</string>
- <string name="msg_vl_error_wrong_key">Mezua ez dago giltza zuzenarekin sinatuta</string>
<string name="msg_vl_clear_meta_file">Agirizena: %s</string>
<string name="msg_vl_clear_meta_mime">MIME mota: %s</string>
<string name="msg_vl_clear_meta_time">Aldaketa ordua: %s</string>
@@ -1013,7 +999,6 @@
<string name="msg_se_success">Sinadura/enkriptaketa eragiketa ongi</string>
<!--Messages for PgpSignEncrypt operation-->
<string name="msg_pse_asymmetric">Giltza publikoak gertatzen enkriptaketarako</string>
- <string name="msg_pse_clearsign_only">Cleartext sarrera sinadura ez dago sostengatuta!</string>
<string name="msg_pse_compressing">Konpresioa gertatzen</string>
<string name="msg_pse_encrypting">Datuak enkriptatzen</string>
<string name="msg_pse_error_bad_passphrase">Sarhitz gaitza!</string>
@@ -1060,37 +1045,15 @@
<string name="msg_import_fetch_error_decode">Akatsa berreskuratutako giltza-uztai dekodeatzerakoan!</string>
<string name="msg_import_fetch_error">Giltza ezin da berreskuratu! (Sare arazoak?)</string>
<string name="msg_import_fetch_keybase">keybase.io-tik berreskuratzen: %s</string>
- <string name="msg_import_fetch_error_keyserver">Ezin da giltza giltza-zerbitzarietatik berreskuratu: %s</string>
<string name="msg_import_fetch_keyserver">Giltza-zerbitzaritik berreskuratzen: %s</string>
<string name="msg_import_fetch_keyserver_ok">Giltza ongi berreskuratu da</string>
<string name="msg_import_keyserver">%s giltza-zerbitzaria erabiltzen</string>
- <string name="msg_import_fingerprint_error">Lortutako giltzaren hatz-aztarna ez dator bat itxarondakoarekin!</string>
- <string name="msg_import_fingerprint_ok">Hatz-aztarna egiaztapena ONGI</string>
<string name="msg_import_merge">Berreskuratutako datuak batzen</string>
<string name="msg_import_merge_error">Akatsa berreskuratutako datuak batzerakoan!</string>
<string name="msg_import_error">Inportatze eragiketa ongi hutsegitea!</string>
<string name="msg_import_error_io">Eragiketa hutsegitea s/i akats bategaitik!</string>
<string name="msg_import_partial">Inportatze eragiketa ongi burutu da, akatsekin!</string>
<string name="msg_import_success">Inportatze eragiketa ongi burutu da!</string>
- <plurals name="msg_export">
- <item quantity="one">Giltza bat esportatzen</item>
- <item quantity="other">%d giltza esportatzen</item>
- </plurals>
- <string name="msg_export_all">Giltza guztiak esportatzen</string>
- <string name="msg_export_public">Giltza publikoa esportatzen %s</string>
- <string name="msg_export_upload_public">%s giltza publikoa igotzen</string>
- <string name="msg_export_secret">%s giltza sekretua esportatzen</string>
- <string name="msg_export_error_no_file">Ez da agirizenik adierazi!</string>
- <string name="msg_export_error_fopen">Akatsa agiria irekitzen!</string>
- <string name="msg_export_error_no_uri">Ez da URI-rik adierazi!</string>
- <string name="msg_export_error_uri_open">Akatsa URI jarioa irekitzerakoan!</string>
- <string name="msg_export_error_storage">Biltegia ez dago gertu idazteko!</string>
- <string name="msg_export_error_db">Datubase akatsa!</string>
- <string name="msg_export_error_io">Sarrera/irteera akatsa!</string>
- <string name="msg_export_error_key">Akatsa giltza datuak aurre-prozesatzerakoan!</string>
- <string name="msg_export_error_upload">Hutsegitea giltza zerbitzarira igotzean! Mesedez egiaztatu zure internet elkarketa.</string>
- <string name="msg_export_success">Esportatze eragiketa ongi burutu da!</string>
- <string name="msg_export_upload_success">Giltza-zerbitzarira igotzea ongi!</string>
<string name="msg_del_error_empty">Ez dago ezer ezabatzeko!</string>
<string name="msg_del_error_multi_secret">Giltza sekretuak banaka bakarrik ezabatu daitezke!</string>
<plurals name="msg_del">
@@ -1113,6 +1076,20 @@
<string name="msg_revoke_key">%s giltza ukatzen</string>
<string name="msg_revoke_key_fail">Hutsegitea giltza ukatzerakoan</string>
<string name="msg_revoke_ok">Giltza ongi ukatu da</string>
+ <!--Linked Identity verification-->
+ <string name="msg_lv">Lotura nortasuna egiaztatzen...</string>
+ <string name="msg_lv_fp_ok">Hatz-aztarna Ongi.</string>
+ <string name="msg_lv_fp_error">Hatz-aztarnak ez datoz bat!</string>
+ <string name="msg_lv_error_twitter_response">Ustekabeko erantzuna Twitter API-tik!</string>
+ <string name="msg_lv_error_github_handle">GiHub kontu kudeaketa ez dator bat erantzunean!</string>
+ <string name="msg_lv_error_github_not_found">Gist-ek bat ez datozen agiriak ditu!</string>
+ <string name="msg_lv_fetch">\'%s\' URI-a lortzen</string>
+ <string name="msg_lv_fetch_ok">Ongi lortuta (HTTP %s)</string>
+ <string name="msg_lv_fetch_error">Zerbitzari akatsa (HTTP %s)</string>
+ <string name="msg_lv_fetch_error_url">URL-a gaizki-osatuta!</string>
+ <string name="msg_lv_fetch_error_io">SI Akatsa!</string>
+ <string name="msg_lv_fetch_error_format">Heuskarri akatsa!</string>
+ <string name="msg_lv_fetch_error_nothing">Baliabidea ez da aurkitu!</string>
<string name="msg_acc_saved">Kontua gordeta</string>
<string name="msg_download_success">Ongi jeitsi da!</string>
<string name="msg_download_no_valid_keys">Ez da baliozko giltzarik aurkitu agiri/gakoan!</string>
@@ -1129,12 +1106,7 @@
<string name="msg_keybase_verification">Giltzabase egiaztapen saiakera %s-rentzat</string>
<string name="msg_keybase_error_dns_fail">DNS TXT Grabaketa berreskurapen hutsegitea</string>
<string name="msg_keybase_error_specific">%s</string>
- <!--Messages for Export Log operation-->
- <string name="msg_export_log_start">Esportatze oharra</string>
- <string name="msg_export_log_error_fopen">Akatsa agiria irekitzerakoan</string>
- <string name="msg_export_log_error_no_file">Ez da agiri izenik adierazi!</string>
- <string name="msg_export_log_error_writing">S/I akatsa agirira idazterakoan!</string>
- <string name="msg_export_log_success">Oharra ongi esportatu da!</string>
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<string name="passp_cache_notif_click_to_clear">Ikutu sarhitzak garbitzeko</string>
<plurals name="passp_cache_notif_n_keys">
@@ -1145,6 +1117,10 @@
<string name="passp_cache_notif_clear">Garbitu Sarhitzak</string>
<string name="passp_cache_notif_pwd">Sarhitza</string>
<!--Keyserver sync-->
+ <string name="keyserver_sync_orbot_notif_title">Zerbitzarietatik Aldiberetzeak Orbot behar du</string>
+ <string name="keyserver_sync_orbot_notif_msg">Ikutu orbot abiarazteko</string>
+ <string name="keyserver_sync_orbot_notif_start">Abiarazi Orbot</string>
+ <string name="keyserver_sync_orbot_notif_ignore">Zuzena</string>
<!--First Time-->
<string name="first_time_text1">Berreskuratu zure pribatutasuna OpenKeychain-ekin!</string>
<string name="first_time_create_key">Sortu nire giltza</string>
@@ -1161,13 +1137,11 @@
<string name="section_certifier_id">Egiaztatzailea</string>
<string name="section_cert">Egiaztagiriaren Xehetasunak</string>
<string name="label_user_id">Nortasuna</string>
- <string name="unknown_uid">&lt;ezezaguna&gt;</string>
+ <string name="unknown_uid"><![CDATA[<ezezaguna>]]></string>
<string name="empty_certs">Ez dago egiaztagiririk giltza honentzat</string>
<string name="certs_text">Hemen balioztatutako berez-egiaztagiriak eta zeure giltzekin sortutako egiaztagiri balioztatuak bakarrik erakusten dira.</string>
<string name="section_uids_to_certify">Nortasunak honako</string>
<string name="certify_text">Inportatzen ari zaren giltzek \"nortasunak\":izenak eta posta helbideak dituzte. Hautatu zehatz-mehatz hauek itxaroten duzunarekin bat datozela baieztatzeko.</string>
- <string name="certify_fingerprint_text">Alderatu erakutsitako hatz-aztarnak, hizkiz-hizki, zure gailuko ereduek erakusten duten batekin.</string>
- <string name="certify_fingerprint_text2">Erakutsitako hatz-aztarnak bat datoz?</string>
<string name="label_revocation">Ukatze Zergaitia</string>
<string name="label_cert_type">Mota</string>
<string name="error_key_not_found">Giltza ez da aurkitu!</string>
@@ -1243,7 +1217,6 @@
<string name="error_nfc_chaining_error">YubiKeyk itxaroten zuen azken agindua kate batean.</string>
<string name="error_nfc_header">YubiKeyk %s byte baliogabe jakinarazi ditu.</string>
<string name="error_nfc_try_again">Saitu berriro</string>
- <string name="error_pin_nodefault">Berezko PIN-a baztertua izan da!</string>
<string name="error_temp_file">Akatsa aldibaterako agiria sortzerakoan.</string>
<string name="btn_delete_original">Ezabatu jatorrizko agiria</string>
<string name="snack_encrypt_filenames_on">Agirizenak enkriptatuta <b>daude</b>.</string>
@@ -1255,8 +1228,8 @@
<string name="error_loading_keys">Akatsa giltzak gertatzerakoan!</string>
<string name="error_empty_log">(akatsa, oharra hutsik)</string>
<string name="error_reading_text">Ezin da irakurri sarrera dekriptatzeko!</string>
- <string name="filename_unknown">&lt;agirizenik ez&gt;</string>
- <string name="filename_unknown_text">&lt;idazki lau datuak&gt;</string>
+ <string name="filename_unknown">Agirizen ezezaguna (klikatu irekitzeko)</string>
+ <string name="filename_unknown_text">Idazkia (klikatu erakusteko)</string>
<string name="intent_show">Erakutsi Sinatutako/Enkriptatutako Edukia</string>
<string name="view_internal">Ikusi OpenKeychain-en</string>
<string name="error_preparing_data">Akatsa datuak gertatzerakoan!</string>
@@ -1272,4 +1245,50 @@
<string name="error_scan_fp">Akatsa hatz-aztarna eskaneatzerakoan!</string>
<string name="error_scan_match">Hatz-aztarnak ez datoz bat!</string>
<string name="error_expiry_past">Iraungitze eguna iraganda dago!</string>
+ <string name="linked_create_https_1_2">Hau egiteko, idazki agiri bat argitaratzen duzu webgune honetan, orduan Lotura Nortasun bat sortu bertara lotuz.</string>
+ <string name="linked_create_https_1_4">Adibidea: https://example.com/pgpkey.txt</string>
+ <string name="linked_create_https_2_2">Hurrengo urratserako, agiri hau gorde eta igo behar duzu.</string>
+ <string name="linked_create_https_2_3">Zihurtatu agiria erdietsigarria dela URI zuzenarekin, orduan egiaztatu zure ezarpena.</string>
+ <string name="linked_create_https_2_4">Egiaztapena ongi egin ondoren, sakatu Amaitu botoia Lotura Nortasuna zure giltza-uztaira gehitzeko eta prozesua amaitzeko.</string>
+ <string name="linked_create_twitter_1_3">Mesedez sartu zure Twitter ikusleiho izena jarraitzeko.</string>
+ <string name="linked_create_twitter_handle">Twitter Kudeaketa</string>
+ <string name="linked_create_twitter_2_1">Klikatu botoia mezua txiotzeko!</string>
+ <string name="linked_create_verify">Egiaztatu</string>
+ <string name="linked_text_clipboard">Idazkia gakora kopiatu da</string>
+ <string name="linked_verified_https">Webgune honen eta giltzaren arteko lotura segurtasunez egiaztatu da. <b>Webgunea egizkoa dela sinesten baduzu.</b>, baieztatu egiaztapen hau zure giltzarekin.</string>
+ <string name="linked_verified_github">GitHub kontu honen eta giltzaren arteko lotura segurtasunez egiaztatu da. <b>Kontua egizkoa dela sinesten baduzu.</b>, baieztatu egiaztapen hau zure giltzarekin.</string>
+ <string name="linked_verified_dns">Domeinu Izen honen eta giltzaren arteko lotura segurtasunez egiaztatu da. <b>Domeinua egizkoa dela sinesten baduzu.</b>, baieztatu egiaztapen hau zure giltzarekin.</string>
+ <string name="linked_verified_twitter">Twitter kontu honen eta giltzaren arteko lotura segurtasunez egiaztatu da. <b>Kontua egizkoa dela sinesten baduzu.</b>, baieztatu egiaztapen hau zure giltzarekin.</string>
+ <string name="linked_verified_secret_https">Guztiak ongi dirudi.</string>
+ <string name="linked_verified_secret_github">Guztiak ongi dirudi.</string>
+ <string name="linked_verified_secret_dns">Guztiak ongi dirudi.</string>
+ <string name="linked_verified_secret_twitter">Guztiak ongi dirudi.</string>
+ <plurals name="linked_id_expand">
+ <item quantity="one">Beste nortasun mota ezezagun bat dago</item>
+ <item quantity="other">Beste %d nortasun mota ezezagun daude</item>
+ </plurals>
+ <!--Other Linked Identity strings-->
+ <string name="linked_select_2">Mesedez hautatu mota bat:</string>
+ <string name="linked_verifying">Egiaztatzen...</string>
+ <string name="linked_verify_success">Egiaztatua!</string>
+ <string name="linked_verify_error">Egiaztapen akatsa!</string>
+ <string name="linked_verify_pending">Egiztatu gabe oraindik</string>
+ <string name="linked_need_verify">Baliabidea egiaztatua izan behar da jarraitu aurretik!</string>
+ <string name="menu_linked_add_identity">Loturatu Kontura</string>
+ <string name="section_linked_identities">Lotura Nortasunak</string>
+ <string name="btn_finish">Amaitu</string>
+ <string name="linked_title_https">Webgunea (HTTPS)</string>
+ <string name="linked_title_dns">Domeinu Izena (DNS)</string>
+ <string name="linked_title_github">GitHub</string>
+ <string name="linked_title_twitter">Twitter</string>
+ <string name="card_linked_identity">Lotura Nortasuna</string>
+ <string name="linked_button_verify">Egiaztatu</string>
+ <string name="linked_button_retry">Saiatu berriro</string>
+ <string name="linked_button_confirm">Baieztatu</string>
+ <string name="linked_button_view">Ikusi</string>
+ <string name="linked_text_verifying">Egiaztatzen...</string>
+ <string name="linked_text_error">Akatsa</string>
+ <string name="linked_text_confirming">Baieztatzen...</string>
+ <string name="linked_ids_more_unknown">%d nortasun mota ezezagun gehiago</string>
+ <string name="title_linked_id_create">Sortu Lotura Nortasuna</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-fa/strings.xml b/OpenKeychain/src/main/res/values-fa/strings.xml
index 86d8ab5cd..99db52230 100644
--- a/OpenKeychain/src/main/res/values-fa/strings.xml
+++ b/OpenKeychain/src/main/res/values-fa/strings.xml
@@ -31,15 +31,12 @@
<string name="title_exchange_keys">مبادلهٔ کلیدها</string>
<string name="title_advanced_key_info">اطلاعات بیشتر</string>
<string name="title_delete_secret_key">آیا کلید \'%s\' خود را پاک می‌کنید؟</string>
- <string name="title_export_log">خروج لاگ</string>
<string name="title_manage_my_keys">مدیریت کلیدهام</string>
<!--section-->
<string name="section_user_ids">هویت‌ها</string>
<string name="section_yubikey">کلید Yubi</string>
<string name="section_should_you_trust">آیا به این کلید اعتماد دارید؟</string>
<string name="section_keys">زیرکلیدها</string>
- <string name="section_cloud_search">جستجوی اینترنت</string>
- <string name="section_proxy_settings">تنظیمات پراکسی</string>
<string name="section_gui">رابط</string>
<string name="section_certify">تأیید</string>
<string name="section_share_key">کلید</string>
@@ -65,11 +62,8 @@
<string name="btn_back">قبلی</string>
<string name="btn_no">نه</string>
<string name="btn_match">اثر انگشت‌ها مطابقت دارد</string>
- <string name="btn_share_encrypted_signed">رمزگذاری و به اشتراک گذاری متن</string>
- <string name="btn_copy_encrypted_signed">رمزگذاری و کپی متن</string>
<string name="btn_create_key">ساخت کلید</string>
<string name="btn_add_files">اضافه کردن فایل(ها)</string>
- <string name="btn_share_decrypted_text">اشتراک گذاری متن رمزگشایی شده</string>
<string name="btn_copy_decrypted_text">کپی متن رمزگشایی شده</string>
<string name="btn_decrypt_clipboard">خواندن از متن کپی‌شده</string>
<string name="btn_decrypt_files">انتخاب فایل ورودی</string>
@@ -83,7 +77,6 @@
<!--menu-->
<string name="menu_preferences">تنظیمات</string>
<string name="menu_help">کمک</string>
- <string name="menu_export_key">پشتیبان‌گیری به فایل</string>
<string name="menu_delete_key">حذف کلید</string>
<string name="menu_manage_keys">مدیریت کلیدهای من</string>
<string name="menu_search">جستجو</string>
@@ -94,8 +87,6 @@
<string name="menu_export_all_keys">خروج همهٔ کلیدها</string>
<string name="menu_update_all_keys">آپدیت همهٔ کلیدها</string>
<string name="menu_advanced">اطلاعات بیشتر</string>
- <string name="menu_certify_fingerprint">تأیید با مقایسهٔ اثر انگشت</string>
- <string name="menu_export_log">خروج لاگ</string>
<string name="menu_keyserver_add">اضافه‌کردن</string>
<!--label-->
<string name="label_message">متن</string>
@@ -112,7 +103,6 @@
<string name="label_file_ascii_armor">فعال‌کردن ASCII Armor</string>
<string name="label_write_version_header">به دیگران اطلاع دهید که شما از OpenKeyChain استفاده می‌کنید</string>
<string name="label_write_version_header_summary">عبارت \'OpenKeychain v2.7\' را در امضاها، متن رمزگذاری‌شده و کلیدها می‌نویسید</string>
- <string name="label_use_default_yubikey_pin">از رمزِ PIN پیش‌فرضِ کلید Yubi استفاده کن</string>
<string name="label_use_num_keypad_for_yubikey_pin">از صفحه‌کلیدِ شماره‌ای برای وارد کردن رمز کلیدِ Yubi استفاده کن</string>
<string name="label_asymmetric_from">امضاء با:</string>
<string name="label_to">رمزگذاری به:</string>
@@ -136,7 +126,6 @@
<string name="label_name">نام</string>
<string name="label_comment">توضیحات</string>
<string name="label_email">ایمیل</string>
- <string name="label_send_key">همگام‌سازی با اینترنت</string>
<string name="label_fingerprint">اثر انگشت</string>
<string name="expiry_date_dialog_title">تعیین تاریخ انقضأ</string>
<string name="label_keyservers_title">سرورِ کلیدها</string>
@@ -146,8 +135,6 @@
<string name="label_enable_compression">فشرده‌کردن</string>
<string name="label_encrypt_filenames">رمزگذاری اسمِ فایل‌ها</string>
<string name="label_hidden_recipients">مخفی‌کردن گیرنده‌ها</string>
- <string name="label_verify_keyserver">بررسی سرورِ کلیدها</string>
- <string name="label_enter_keyserver_url">آدرس URL سرورِ کلید را وارد کنید</string>
<string name="label_keyserver_dialog_delete">حذف سرورهای کلید</string>
<string name="label_theme">قالب</string>
<string name="pref_keyserver">سرورهای کلید OpenPGP</string>
@@ -170,7 +157,6 @@
<string name="no_filemanager_installed">برنامهٔ مدیریتِ فایل سازگاری نصب نیست.</string>
<string name="passphrases_do_not_match">رمز عبور‌ها مطابقت ندارند.</string>
<string name="passphrase_must_not_be_empty">لطفاً یک رمزعبور وارد کنید.</string>
- <string name="passphrase_for_symmetric_encryption">رمزگذاری متقارن(فقط با یک رمزعبور)</string>
<string name="passphrase_for">وارد کردن رمز عبور برای \'%s\'</string>
<string name="pin_for">وارد کردن رمزِ پین برای \'%s\'</string>
<string name="keys_exported">%d کلید با موفقیت خارج شد.</string>
@@ -178,7 +164,6 @@
<string name="key_copied_to_clipboard">کلید در حافظه کپی شده است!</string>
<string name="fingerprint_copied_to_clipboard">اثر انگشت در حافظه کپی شده است!</string>
<string name="select_key_to_certify">لطفاً یک کلید برای تأیید کردن انتخاب کنید!</string>
- <string name="key_too_big_for_sharing">کلید خیلی بزرگ است و نمی‌توان آن را از این طریق به اشتراک گذاشت!</string>
<string name="text_copied_to_clipboard">متن در حافظه کپی شده است!</string>
<!--errors
no punctuation, all lowercase,
@@ -260,13 +245,6 @@
<string name="user_id_info_invalid_title">نامعتبر</string>
<string name="user_id_info_invalid_text">هویت مشکل دارد!</string>
<!--Key trust-->
- <string name="key_trust_already_verified">شما قبلاً این کلید را تأیید کرده‌اید!</string>
- <string name="key_trust_it_is_yours">این یکی از کلیدهای‌تان است!</string>
- <string name="key_trust_maybe">این کلید نه لغو شده و نه منقضی شده است.\nشما آن را تأیید نکرده‌اید، ولی می‌توانید اعتماد به آن کلید را انتخاب کنید.</string>
- <string name="key_trust_revoked">این کلید توسط صاحب‌اش لغو شده است. نباید به آن اعتماد کنید.</string>
- <string name="key_trust_expired">این کلید منقضی شده است. نباید به آن اعتماد کنید.</string>
- <string name="key_trust_old_keys">اگر از این برای رمزگشاییِ یک پیغام قدیمی مربوط به قبل از منقضی شدن‌اش استفاده می‌کنید، مشکلی نیست.</string>
- <string name="key_trust_no_cloud_evidence">هیچ دلیلی برای اعتماد به این کلید بر روی اینترنت نیست.</string>
<string name="key_trust_start_cloud_search">آغاز جستجو</string>
<!--keybase proof stuff-->
<string name="keybase_narrative_twitter">روی Twitter پست می‌کند به عنوان %s</string>
@@ -319,8 +297,9 @@
<!--Messages for VerifySignedLiteralData operation-->
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Linked Identity verification-->
<!--Messages for Keybase Verification operation-->
- <!--Messages for Export Log operation-->
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<!--Keyserver sync-->
<!--First Time-->
@@ -330,4 +309,5 @@
<!--TODO: rename all the things!-->
<!--<string name="enter_passphrase_twice">Enter password twice</string>-->
<!--<string name="nfc_text">Please place a NFC tag near your device</string>-->
+ <!--Other Linked Identity strings-->
</resources>
diff --git a/OpenKeychain/src/main/res/values-fi/strings.xml b/OpenKeychain/src/main/res/values-fi/strings.xml
index a8bbd7f79..1b9284935 100644
--- a/OpenKeychain/src/main/res/values-fi/strings.xml
+++ b/OpenKeychain/src/main/res/values-fi/strings.xml
@@ -2,94 +2,143 @@
<resources>
<!--GENERAL: Please put all strings inside quotes as described in example 1 on
http://developer.android.com/guide/topics/resources/string-resource.html (scroll down to "Escaping apostrophes and quotes").-->
+ <string name="app_name">OpenKeychain</string>
<!--title-->
- <string name="title_decrypt">Pura Salaus</string>
+ <string name="title_encrypt_text">Salaa</string>
+ <string name="title_encrypt_files">Salaa</string>
+ <string name="title_decrypt">Pura salaus</string>
<string name="title_add_subkey">Lisää aliavain</string>
<string name="title_edit_key">Muokkaa avainta</string>
<string name="title_preferences">Asetukset</string>
<string name="title_api_registered_apps">Sovellukset</string>
+ <string name="title_key_server_preference">OpenPGP-avainpalvelimet</string>
+ <string name="title_change_passphrase">Vaihda salasana</string>
<string name="title_share_fingerprint_with">Jaa sormenjälki...</string>
<string name="title_share_key">Jaa avain...</string>
<string name="title_share_file">Jaa tiedosto...</string>
- <string name="title_encrypt_to_file">Salaa Tiedostoon</string>
- <string name="title_decrypt_to_file">Pura Tiedostoon</string>
- <string name="title_import_keys">Tuo Avaimia</string>
- <string name="title_key_not_found">Avainta Ei Löydy</string>
- <string name="title_send_key">Lähetä Avainpalvelimelle</string>
- <string name="title_key_details">Avaimen Tiedot</string>
+ <string name="title_share_message">Jaa teksti...</string>
+ <string name="title_encrypt_to_file">Salaa tiedostoon</string>
+ <string name="title_decrypt_to_file">Pura salaus tiedostoon</string>
+ <string name="title_import_keys">Tuo avaimia</string>
+ <string name="title_export_key">Varmuuskopioi avain</string>
+ <string name="title_export_keys">Varmuuskopioi avaimet</string>
+ <string name="title_key_not_found">Avainta ei löydy</string>
+ <string name="title_send_key">Lähetä avainpalvelimelle</string>
+ <string name="title_certify_key">Vahvista avain</string>
+ <string name="title_key_details">Avaimen tiedot</string>
<string name="title_help">Apua</string>
<string name="title_log_display">Loki</string>
- <string name="title_exchange_keys">Vaihda Avaimia</string>
+ <string name="title_exchange_keys">Vaihda avaimia</string>
+ <string name="title_manage_my_keys">Hallitse avaimiani</string>
<!--section-->
<string name="section_user_ids">Identiteetit</string>
+ <string name="section_yubikey">YubiKey</string>
<string name="section_keys">Aliavaimet</string>
- <string name="section_cloud_search">Pilvihaku</string>
- <string name="section_actions">Toiminteet</string>
+ <string name="section_gui">Käyttöliittymä</string>
+ <string name="section_experimental_features">Kokeelliset ominaisuudet</string>
+ <string name="section_certify">Vahvista</string>
+ <string name="section_actions">Toiminnot</string>
<string name="section_share_key">Avain</string>
<string name="section_key_server">Avainpalvelin</string>
<string name="section_fingerprint">Sormenjälki</string>
+ <string name="section_encrypt">Salaa</string>
+ <string name="section_decrypt">Pura salaus / todenna</string>
<!--button-->
<string name="btn_decrypt_verify_file">Pura, todenna ja tallenna tiedosto</string>
<string name="btn_encrypt_share_file">Salaa ja jaa tiedosto</string>
+ <string name="btn_encrypt_save_file">Salaa ja tallenna tiedosto</string>
+ <string name="btn_save_file">Tallenna tiedost</string>
+ <string name="btn_save">Tallenna</string>
+ <string name="btn_view_log">Katso loki</string>
<string name="btn_do_not_save">Peruuta</string>
<string name="btn_delete">Poista</string>
<string name="btn_no_date">Ei umpeutumisaikaa</string>
<string name="btn_okay">OK</string>
- <string name="btn_export_to_server">Lataa Avainpalvelimelle</string>
+ <string name="btn_export_to_server">Lataa avainpalvelimelle</string>
<string name="btn_next">Seuraava</string>
<string name="btn_back">Takaisin</string>
+ <string name="btn_no">Ei</string>
+ <string name="btn_match">Sormenjäljet täsmäävät</string>
<string name="btn_view_cert_key">Näytä varmennusavain</string>
<string name="btn_create_key">Luo avain</string>
<string name="btn_add_files">Lisää tiedosto(ja)</string>
+ <string name="btn_unlock">Avaa lukitus</string>
+ <string name="btn_add_keyserver">Lisä</string>
+ <string name="btn_save_default">Tallenna oletukseksi</string>
+ <string name="btn_saved">Tallennettu!</string>
<!--menu-->
<string name="menu_preferences">Asetukset</string>
<string name="menu_help">Apua</string>
<string name="menu_delete_key">Poista avain</string>
+ <string name="menu_manage_keys">Hallitse avaimiani</string>
<string name="menu_search">Etsi</string>
- <string name="menu_beam_preferences">Beam asetukset</string>
+ <string name="menu_nfc_preferences">NFC-asetukset</string>
+ <string name="menu_beam_preferences">Beam-asetukset</string>
<string name="menu_encrypt_to">Salaa...</string>
<string name="menu_select_all">Valitse kaikki</string>
<string name="menu_export_all_keys">Vie kaikki avaimet</string>
+ <string name="menu_update_all_keys">Päivitä kaikki avaimet</string>
+ <string name="menu_keyserver_add">Lisää</string>
<!--label-->
+ <string name="label_message">Teksti</string>
<string name="label_file">Tiedosto</string>
<string name="label_files">Tiedosto(t)</string>
<string name="label_file_colon">Tiedosto:</string>
+ <string name="label_no_passphrase">Ei salasanaa</string>
+ <string name="label_passphrase">Salasan</string>
<string name="label_unlock">Avataan...</string>
+ <string name="label_passphrase_again">Toista salasana</string>
+ <string name="label_show_passphrase">Näytä salasana</string>
<string name="label_algorithm">Algoritmi</string>
- <string name="label_ascii_armor">Tiedosto ASCII Armor</string>
+ <string name="label_ascii_armor">Tiedoston ASCII Armor</string>
<string name="label_file_ascii_armor">Käytä ASCII Armoria</string>
<string name="label_write_version_header">Anna muiden tietää että käytät OpenKeychainia</string>
<string name="label_write_version_header_summary">Kirjoittaa \'OpenKeychain v2.7\' OpenPGP-allekirjoituksiin, kryptattuun tekstiin sekä vietyihin avaimiin</string>
- <string name="label_use_default_yubikey_pin">Käytä vakiota YubiKey PIN:iä</string>
<string name="label_use_num_keypad_for_yubikey_pin">Käytä numeerista näppäimistöä YuniKey PIN:iin</string>
- <string name="label_label_use_default_yubikey_pin_summary">Käyttää vakio-PIN:iä (123456) käyttääkseen YubiKeyssejä NFC kautta</string>
<string name="label_to">Salaa:</string>
<string name="label_delete_after_decryption">Poista salauksen purkamisen jälkeen</string>
<string name="label_encryption_algorithm">Salausalgoritmi</string>
<string name="label_hash_algorithm">Tiivistealgoritmi</string>
<string name="label_file_compression">Tiedoston pakkaus</string>
<string name="label_key_id">Avaimen ID</string>
+ <string name="label_key_created">Avain luotu %s</string>
<string name="label_creation">Luontiaika</string>
<string name="label_expiry">Umpeutumisaika</string>
<string name="label_usage">Käyttö</string>
- <string name="label_key_size">Avaimen Koko</string>
- <string name="label_ecc_curve">Elliptinen Käyrä</string>
+ <string name="label_key_size">Avaimen koko</string>
+ <string name="label_ecc_curve">Elliptinen käyrä</string>
<string name="label_main_user_id">Pääidentiteetti</string>
<string name="label_name">Nimi</string>
<string name="label_comment">Kommentti</string>
<string name="label_email">Email</string>
- <string name="label_send_key">Synkronoi pilveen</string>
<string name="label_fingerprint">Sormenjälki</string>
<string name="expiry_date_dialog_title">Aseta umpeutumispäivämäärä</string>
+ <string name="label_keyservers_title">Avainpalvelimet</string>
+ <string name="label_selected_keyserver_title">Valittu avainpalvelin</string>
<string name="label_preferred">ensisijainen</string>
+ <string name="label_enable_compression">Ota pakkaus käyttöön</string>
+ <string name="label_encrypt_filenames">Salaa tiedostojen nimet</string>
+ <string name="label_keyserver_dialog_delete">Poista avainpalvelin</string>
+ <string name="label_theme">Teema</string>
+ <string name="pref_keyserver">OpenPGP-avainpalvelimet</string>
+ <string name="pref_keybase">keybase.io</string>
+ <string name="pref_keybase_summary">Etsi avaimia osoitteesta keybase.io</string>
+ <string name="label_sync_settings_keyserver_title">Päivitä avaimet automaattisesti</string>
<!--label shown in Android settings under the OpenKeychain account-->
+ <string name="keyserver_sync_settings_title">Päivitä avaimet automaattisesti</string>
+ <string name="label_experimental_settings_desc_title">Varoitus</string>
<!--Proxy Preferences-->
+ <string name="pref_proxy_tor_title">Ota Tor käyttöö</string>
+ <string name="pref_proxy_tor_summary">Orbot tulee olla asennettu</string>
<!--proxy type choices and values-->
+ <string name="pref_proxy_type_choice_http">HTTP</string>
+ <string name="pref_proxy_type_choice_socks">SOCKS</string>
<!--OrbotHelper strings-->
<!--InstallDialogFragment strings-->
+ <string name="orbot_install_dialog_install">Asenna</string>
+ <string name="orbot_install_dialog_cancel">Peruuta</string>
<!--StartOrbotDialogFragment strings-->
- <string name="user_id_no_name">&lt;ei nimeä&gt;</string>
- <string name="none">&lt;ei mitään&gt;</string>
+ <string name="orbot_start_dialog_cancel">Peruuta</string>
<plurals name="n_keys">
<item quantity="one">1 avain</item>
<item quantity="other">%d avainta</item>
@@ -98,7 +147,7 @@
<item quantity="one">%d avainpalvelin</item>
<item quantity="other">%d avainpalvelinta</item>
</plurals>
- <string name="secret_key">Salainen Avain:</string>
+ <string name="secret_key">Salainen avain:</string>
<!--choice-->
<string name="choice_none">Ei mitään</string>
<string name="choice_15secs">15 sek.</string>
@@ -112,7 +161,8 @@
<string name="choice_2hours">2 tuntia</string>
<string name="choice_4hours">4 tuntia</string>
<string name="choice_8hours">8 tuntia</string>
- <string name="choice_forever">aina</string>
+ <string name="choice_forever">ikuisesti</string>
+ <string name="choice_select_cert">Valitse avain</string>
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
@@ -121,22 +171,43 @@
<string name="filemanager_title_open">Avaa...</string>
<string name="error">Virhe</string>
<string name="error_message">Virhe: %s</string>
+ <string name="theme_dark">Tumma</string>
+ <string name="theme_light">Vaalea</string>
<!--key flags-->
<string name="flag_certify">Varmenna</string>
<string name="flag_sign">Allekirjoita</string>
<string name="flag_encrypt">Salaa</string>
<string name="flag_authenticate">Autentikoi</string>
<!--sentences-->
+ <string name="wrong_passphrase">Väärä salasana</string>
<string name="no_filemanager_installed">Yhteensopivaa tiedostonhallintaa ei ole asennettu.</string>
- <string name="passphrase_for_symmetric_encryption">Symmetrinen salaus.</string>
+ <string name="passphrases_do_not_match">Salasanat eivät täsmää.</string>
+ <string name="passphrase_must_not_be_empty">Syötäthän salasanan.</string>
<string name="pin_for">Syötä PIN \'%s\':lle</string>
+ <string name="no_file_selected">Tiedostoa ei ole valittu.</string>
<!--errors
no punctuation, all lowercase,
they will be put after "error_message", e.g. "Error: file not found"-->
+ <string name="error_wrong_passphrase">väärä salasana</string>
<!--errors without preceeding Error:-->
<!--results shown after decryption/verification-->
+ <string name="decrypt_result_encrypted">Salattu</string>
+ <string name="decrypt_result_not_encrypted">Ei salattu</string>
+ <string name="decrypt_result_insecure">Turvaton salaus</string>
+ <string name="decrypt_result_action_show">Näytä</string>
+ <string name="decrypt_invalid_button">Ymmärrän riskit, näytä se!</string>
<!--Add keys-->
+ <string name="add_keys_my_key">Minun avain:</string>
<!--progress dialogs, usually ending in '…'-->
+ <string name="progress_done">Tehty.</string>
+ <string name="progress_cancel">Peruuta</string>
+ <string name="progress_cancelling">peruutetaan...</string>
+ <string name="progress_saving">tallennetaan...</string>
+ <string name="progress_importing">tuodaan...</string>
+ <string name="progress_updating">Päivitetään avaimia...</string>
+ <string name="progress_exporting">viedään...</string>
+ <string name="progress_uploading">lähetetään...</string>
+ <string name="progress_building_key">rakennetaan avainta...</string>
<!--action strings-->
<!--key bit length selections-->
<!--elliptic curve names-->
@@ -183,17 +254,53 @@
<!--Other messages used in OperationLogs-->
<!--Messages for DecryptVerify operation-->
<!--Messages for VerifySignedLiteralData operation-->
+ <string name="msg_vl_ok">OK</string>
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Linked Identity verification-->
<!--Messages for Keybase Verification operation-->
- <!--Messages for Export Log operation-->
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<!--Keyserver sync-->
<!--First Time-->
<!--unsorted-->
+ <string name="label_cert_type">Tyyppi</string>
+ <string name="key_no_passphrase">ei salasanaa</string>
+ <string name="key_unavailable">ei saatavilla</string>
+ <string name="unknown_algorithm">tunnistamaton</string>
+ <string name="contact_show_key">Näytä avain (%s)</string>
+ <string name="key_colon">Avain:</string>
<!--Android Account-->
<!--Passphrase wizard-->
<!--TODO: rename all the things!-->
<!--<string name="enter_passphrase_twice">Enter password twice</string>-->
<!--<string name="nfc_text">Please place a NFC tag near your device</string>-->
+ <string name="progress_processing">Käsitellään...</string>
+ <string name="linked_create_twitter_1_3">Syötäthän Twitter-näyttönimesi jatkaaksesi.</string>
+ <string name="linked_create_twitter_handle">Twitter-välikappale</string>
+ <string name="linked_create_twitter_2_1">Klikkaa kumpaa tahansa nappia twiitataksesi viestin!</string>
+ <string name="linked_create_verify">Todenna</string>
+ <string name="linked_text_clipboard">Teksti on kopioitu leikepöydälle</string>
+ <!--Other Linked Identity strings-->
+ <string name="linked_verifying">Todennetaan...</string>
+ <string name="linked_verify_success">Todennettu!</string>
+ <string name="linked_verify_error">Virhe todennuksessa!</string>
+ <string name="linked_verify_pending">Ei vielä todennettu</string>
+ <string name="linked_need_verify">Resurssi täytyy todentaa ennenkuin voit jatkaa!</string>
+ <string name="menu_linked_add_identity">Linkitä tunnukseen</string>
+ <string name="section_linked_identities">Linkitetyt identiteetit</string>
+ <string name="linked_title_https">Verkkosivu (HTTPS)</string>
+ <string name="linked_title_dns">Domain-nimi (DNS)</string>
+ <string name="linked_title_github">GitHub</string>
+ <string name="linked_title_twitter">Twitter</string>
+ <string name="card_linked_identity">Linkitetty identiteetti</string>
+ <string name="linked_button_verify">Todenna</string>
+ <string name="linked_button_retry">Yritä uudelleen</string>
+ <string name="linked_button_confirm">Vahvista</string>
+ <string name="linked_button_view">Näkymä</string>
+ <string name="linked_text_verifying">Todennetaan...</string>
+ <string name="linked_text_error">Virhe</string>
+ <string name="linked_text_confirming">Vahvistetaan...</string>
+ <string name="linked_ids_more_unknown">Vielä %d tunnistamatonta identiteettityyppiä</string>
+ <string name="title_linked_id_create">Luo linkitetty identiteetti</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-fr/strings.xml b/OpenKeychain/src/main/res/values-fr/strings.xml
index 4a6c2bbfe..489774276 100644
--- a/OpenKeychain/src/main/res/values-fr/strings.xml
+++ b/OpenKeychain/src/main/res/values-fr/strings.xml
@@ -9,6 +9,7 @@
<string name="title_decrypt">Déchiffrer</string>
<string name="title_add_subkey">Ajouter une sous-clef</string>
<string name="title_edit_key">Modifier une clef</string>
+ <string name="title_linked_create">Créer une identité reliée</string>
<string name="title_preferences">Paramètres</string>
<string name="title_api_registered_apps">Applis</string>
<string name="title_key_server_preference">Serveurs de clefs OpenPGP</string>
@@ -31,21 +32,25 @@
<string name="title_exchange_keys">Échanger des clefs</string>
<string name="title_advanced_key_info">Informations détaillées</string>
<string name="title_delete_secret_key">Supprimer VOTRE clef « %s » ?</string>
- <string name="title_export_log">Exporter le journal</string>
<string name="title_manage_my_keys">Gérer mes clefs</string>
<!--section-->
<string name="section_user_ids">identités</string>
- <string name="section_yubikey">ClefYubi</string>
+ <string name="section_yubikey">Yubikey</string>
<string name="section_linked_system_contact">Contact système relié</string>
+ <string name="section_keybase_proofs">Preuves keybase.io</string>
<string name="section_should_you_trust">Devriez-vous faire confiance à cette clef ?</string>
<string name="section_proof_details">Vérification de preuve</string>
- <string name="section_cloud_evidence">Preuves provenant du nuage</string>
<string name="section_keys">Sous-clefs</string>
- <string name="section_cloud_search">Recherche nuagique</string>
- <string name="section_passphrase_cache">Gestion des mots de passe/NIP</string>
- <string name="section_proxy_settings">Paramètres du mandataire</string>
+ <string name="section_cloud_search">Recherche de clefs</string>
+ <string name="section_cloud_search_summary">Serveur de clefs, keybase.io</string>
+ <string name="section_passphrase_cache">Mots de passe et NIP</string>
+ <string name="section_passphrase_cache_summary">Gestion, interface utilisateur, délai de mémorisation</string>
+ <string name="section_proxy_settings">Anonymat du réseau</string>
+ <string name="section_proxy_settings_summary">Tor, paramètres du mandataire</string>
<string name="section_gui">Interface</string>
- <string name="section_sync_settings">Paramètres de synchro</string>
+ <string name="section_sync_settings">Synchronisation</string>
+ <string name="section_sync_settings_summary">Mises à jour automatique des clefs, relation des contacts</string>
+ <string name="section_experimental_features">Fonctions expérimentales</string>
<string name="section_certify">Confirmer</string>
<string name="section_actions">Actions</string>
<string name="section_share_key">Clef</string>
@@ -71,12 +76,11 @@
<string name="btn_back">Retour</string>
<string name="btn_no">Non</string>
<string name="btn_match">Les empreintes correspondent</string>
- <string name="btn_share_encrypted_signed">Chiffrer et partager du texte</string>
- <string name="btn_copy_encrypted_signed">Chiffrer et copier du texte</string>
+ <string name="btn_share_encrypted_signed">Chiffrer/signer et partager le texte</string>
+ <string name="btn_copy_encrypted_signed">Chiffrer/signer et copier le texte</string>
<string name="btn_view_cert_key">Voir la clef de certification</string>
<string name="btn_create_key">Créer la clef</string>
<string name="btn_add_files">Ajouter un/des fichier(s)</string>
- <string name="btn_share_decrypted_text">Partager le texte déchiffré</string>
<string name="btn_copy_decrypted_text">Copier le texte déchiffré</string>
<string name="btn_decrypt_clipboard">Lire du presse-papiers</string>
<string name="btn_decrypt_files">Choisir le fichier d\'entrée</string>
@@ -90,7 +94,6 @@
<!--menu-->
<string name="menu_preferences">Paramètres</string>
<string name="menu_help">Aide</string>
- <string name="menu_export_key">Sauvegarder vers un fichier</string>
<string name="menu_delete_key">Supprimer la clef</string>
<string name="menu_manage_keys">Gérer mes clefs</string>
<string name="menu_search">Rechercher</string>
@@ -101,8 +104,7 @@
<string name="menu_export_all_keys">Exporter toutes les clefs</string>
<string name="menu_update_all_keys">Mettre toutes les clefs à jour</string>
<string name="menu_advanced">Informations détaillées</string>
- <string name="menu_certify_fingerprint">Confirmer par une comparaison d\'empreinte</string>
- <string name="menu_export_log">Exporter le journal</string>
+ <string name="menu_certify_fingerprint">Confirmer par empreinte</string>
<string name="menu_keyserver_add">Ajouter</string>
<!--label-->
<string name="label_message">Texte</string>
@@ -119,9 +121,7 @@
<string name="label_file_ascii_armor">Activer l\'armure ASCII</string>
<string name="label_write_version_header">Faire savoir aux autres que vous utilisez OpenKeychain</string>
<string name="label_write_version_header_summary">Ajoute « OpenKeychain v2.7 » aux signatures OpenPGP, aux cryptogrammes et aux clefs exportées</string>
- <string name="label_use_default_yubikey_pin">Utiliser le NIP par défaut de la ClefYubi</string>
- <string name="label_use_num_keypad_for_yubikey_pin">Utiliser le pavé numérique pour le NIP de la ClefYubi</string>
- <string name="label_label_use_default_yubikey_pin_summary">Utilise le NIP par défaut (123456) pour accéder aux ClefsYubi par la NFC</string>
+ <string name="label_use_num_keypad_for_yubikey_pin">Utiliser le pavé numérique pour le NIP de la Yubikey</string>
<string name="label_asymmetric_from">Signer avec :</string>
<string name="label_to">Chiffrer pour :</string>
<string name="label_delete_after_encryption">Supprimer les fichiers après chiffrement</string>
@@ -145,7 +145,7 @@
<string name="label_name">Nom</string>
<string name="label_comment">Commentaire</string>
<string name="label_email">Courriel</string>
- <string name="label_send_key">Synchroniser avec le nuage</string>
+ <string name="label_send_key">Synchroniser par l\'Internet</string>
<string name="label_fingerprint">Empreinte</string>
<string name="expiry_date_dialog_title">Définir une date d\'expiration</string>
<string name="label_keyservers_title">Serveurs de clefs</string>
@@ -155,8 +155,6 @@
<string name="label_enable_compression">Activer la compression</string>
<string name="label_encrypt_filenames">Chiffrer les nom de fichier</string>
<string name="label_hidden_recipients">Cacher les destinataires</string>
- <string name="label_verify_keyserver">Vérifier le serveur de clefs</string>
- <string name="label_enter_keyserver_url">Saisir l\'URL du serveur de clefs</string>
<string name="label_keyserver_dialog_delete">Supprimer le serveur de clefs</string>
<string name="label_theme">Thème</string>
<string name="pref_keyserver">Serveurs de clefs OpenPGP</string>
@@ -166,11 +164,18 @@
<string name="label_sync_settings_keyserver_title">Mettre les clefs à jour automatiquement</string>
<string name="label_sync_settings_keyserver_summary_on">Les clefs de plus d\'une semaine sont misent à jour à partir du serveur de clefs</string>
<string name="label_sync_settings_keyserver_summary_off">Les clefs ne sont pas mises à jour automatiquement</string>
- <string name="label_sync_settings_contacts_title">Synchroniser les contacts avec les clefs</string>
- <string name="label_sync_settings_contacts_summary_on">Les clefs sont reliées aux contacts dont les adresses courriels correspondantes, ce qui se passe complètement hors ligne</string>
+ <string name="label_sync_settings_contacts_title">Relier les clefs aux contacts</string>
+ <string name="label_sync_settings_contacts_summary_on">Relier les clefs aux contacts d\'après les noms et les adresses courriel. Cela se passe entièrement hors ligne sur votre appareil.</string>
<string name="label_sync_settings_contacts_summary_off">Les nouvelles clefs ne seront pas reliées aux contacts</string>
<!--label shown in Android settings under the OpenKeychain account-->
<string name="keyserver_sync_settings_title">Mettre les clefs à jour automatiquement</string>
+ <string name="label_experimental_settings_desc_title">Avertissement</string>
+ <string name="label_experimental_settings_desc_summary">Ces fonctions ne sont pas encore complétées et n\'ont pas fait l\'objet de recherche sur leur convivialité ni leur sécurité. Par conséquent, ne vous fiez pas à leur sécurité et veuillez ne pas rapporter les problèmes que vous rencontrez.</string>
+ <string name="label_experimental_settings_linked_identities_title">Identités reliées</string>
+ <string name="label_experimental_settings_linked_identities_summary">Relier les clefs à Twitter, GitHub, à des sites Web ou DNS (semblable à keybase.io mais décentralisé)</string>
+ <string name="label_experimental_settings_keybase_title">Preuves keybase.io</string>
+ <string name="label_experimental_settings_keybase_summary">Contacter keybase.io pour obtenir des preuves de clef et les montrer chaque fois qu\'une clef est affichée</string>
+ <string name="label_experimental_settings_theme_summary">(Les icônes et de nombreux écrans ne sont pas encore adaptés au thème sombre)</string>
<!--Proxy Preferences-->
<string name="pref_proxy_tor_title">Activer Tor</string>
<string name="pref_proxy_tor_summary">Orbot doit être installé</string>
@@ -184,22 +189,18 @@
<string name="pref_proxy_type_choice_http">HTTP</string>
<string name="pref_proxy_type_choice_socks">SOCKS</string>
<!--OrbotHelper strings-->
- <string name="orbot_ignore_tor">Ne pas utiliser Tor</string>
<!--InstallDialogFragment strings-->
<string name="orbot_install_dialog_title">Installer Orbot pour utiliser Tor ?</string>
<string name="orbot_install_dialog_install">Installer</string>
<string name="orbot_install_dialog_content">Orbot doit être installé et doit relayer le trafic. Voulez-vous l\'installer maintenant ?</string>
<string name="orbot_install_dialog_cancel">Annuler</string>
- <string name="orbot_install_dialog_ignore_tor">Ne pas utiliser Tor</string>
<!--StartOrbotDialogFragment strings-->
<string name="orbot_start_dialog_title">Démarrer Orbot ?</string>
- <string name="orbot_start_dialog_content">Orbot ne semble pas tourner. Voulez-vous le démarrer et vous connecter à Tor ?</string>
<string name="orbot_start_btn">Démarrer Orbot</string>
<string name="orbot_start_dialog_start">Démarrer Orbot</string>
<string name="orbot_start_dialog_cancel">Annuler</string>
- <string name="orbot_start_dialog_ignore_tor">Ne pas utiliser Tor</string>
- <string name="user_id_no_name">&lt;aucun nom&gt;</string>
- <string name="none">&lt;aucune&gt;</string>
+ <string name="user_id_no_name"><![CDATA[<no name>]]></string>
+ <string name="none"><![CDATA[<none>]]></string>
<plurals name="n_keys">
<item quantity="one">1 clef</item>
<item quantity="other">%d clefs</item>
@@ -223,6 +224,7 @@
<string name="choice_4hours">4 heures</string>
<string name="choice_8hours">8 heures</string>
<string name="choice_forever">pour toujours</string>
+ <string name="choice_select_cert">Choisir une clef</string>
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
@@ -243,14 +245,13 @@
<string name="no_filemanager_installed">Aucun gestionnaire de fichiers compatible installé.</string>
<string name="passphrases_do_not_match">Les mots de passe ne correspondent pas.</string>
<string name="passphrase_must_not_be_empty">Veuillez saisir un mot de passe.</string>
- <string name="passphrase_for_symmetric_encryption">Chriffrement symétrique.</string>
<string name="passphrase_for">Saisir le mot de passe pour « %s »</string>
<string name="pin_for">Saisir le NIP pour « %s »</string>
- <string name="yubikey_pin_for">Saisir le NIP pour accéder à la ClefYubi pour « %s »</string>
- <string name="nfc_text">Tenez la ClefYubi contre le logo NFC au dos de votre appareil.</string>
- <string name="nfc_wait">Conservez la ClefYubi contre le dos !</string>
- <string name="nfc_finished">Retirez la ClefYubi maintenant.</string>
- <string name="nfc_try_again_text">Retirez la ClefYubi maintenant et appuyez sur RESSAYER.</string>
+ <string name="yubikey_pin_for">Saisir le NIP pour accéder à la Yubikey pour « %s »</string>
+ <string name="nfc_text">Tenez la Yubikey contre le logo NFC au dos de votre appareil.</string>
+ <string name="nfc_wait">Gardez la Yubikey contre le dos !</string>
+ <string name="nfc_finished">Retirez la Yubikey maintenant.</string>
+ <string name="nfc_try_again_text">Retirez la Yubikey maintenant et appuyez sur RESSAYER.</string>
<string name="file_delete_confirmation_title">Supprimer les fichiers originaux ?</string>
<string name="file_delete_confirmation">Les fichiers suivants seront détruits : %s</string>
<string name="file_delete_successful">%1$d fichiers sur %2$d ont déjà été supprimés. %3$s</string>
@@ -266,7 +267,6 @@
<string name="specify_backup_dest_secret_single">Une sauvegarde complète de votre clef sera faite. Veuillez spécifier un fichier de destination.\nAVERTISSEMENT : le fichier sera écrasé s\'il existe !</string>
<string name="specify_backup_dest_secret">Une sauvegarde complète de toutes les clefs, la vôtre incluse, sera faite. Veuillez spécifier un fichier de destination.\nAVERTISSEMENT : le fichier sera écrasé s\'il existe !</string>
<string name="key_deletion_confirmation_multi">Voulez-vous vraiment supprimer toutes les clefs sélectionnées ?</string>
- <string name="secret_key_deletion_confirmation">Après suppression vous ne pourrez plus lire les messages chiffrés avec cette clef et vous perdrez toutes les confirmations de clefs faites avec elle !</string>
<string name="public_key_deletetion_confirmation">Supprimer la clef \'%s\' ?</string>
<string name="also_export_secret_keys">Importer aussi les clefs secrètes</string>
<string name="reinstall_openkeychain">Vous venez de rencontrer un bogue connu d\'Android. Veuillez réinstaller OpenKeychain si voulez relier vos contacts avec des clefs.</string>
@@ -275,18 +275,16 @@
<string name="no_keys_exported">Aucune clef exportée.</string>
<string name="key_creation_el_gamal_info">Note : seules les sous-clefs prennent en charge ElGamal.</string>
<string name="key_not_found">Clef %08X introuvable.</string>
- <string name="specify_file_to_export_log_to">Veuillez spécifier le fichier vers lequel exporter. \nAVERTISSEMENT : le fichier sera écrasé s\'il existe.</string>
<plurals name="bad_keys_encountered">
<item quantity="one">%d mauvaise clef secrète ignorée. Vous avez peut-être exporté avec l\'option\n --export-secret-subkeys\nAssurez-vous d\'exporter plutôt avec\n --export-secret-keys.</item>
<item quantity="other">%d mauvaises clefs secrètes ignorées. Vous avez peut-être exporté avec l\'option\n --export-secret-subkeys\nAssurez-vous d\'exporter plutôt avec\n --export-secret-keys.</item>
</plurals>
<string name="list_empty">Cette liste est vide !</string>
<string name="nfc_successful">Clef envoyée par Beam NFC avec succès |</string>
- <string name="key_copied_to_clipboard">La clef a été copié vers le presse-papiers !</string>
- <string name="fingerprint_copied_to_clipboard">L\'empreinte a été copié vers le presse-papiers !</string>
+ <string name="key_copied_to_clipboard">La clef a été copié dans le presse-papiers !</string>
+ <string name="fingerprint_copied_to_clipboard">L\'empreinte a été copié dans le presse-papiers !</string>
<string name="select_key_to_certify">Veuillez sélectionner une clef à utiliser pour la confirmation !</string>
- <string name="key_too_big_for_sharing">La clef est trop grosse pour être partagée ainsi !</string>
- <string name="text_copied_to_clipboard">La texte a été copié vers le presse-papiers !</string>
+ <string name="text_copied_to_clipboard">La texte a été copié dans le presse-papiers !</string>
<!--errors
no punctuation, all lowercase,
they will be put after "error_message", e.g. "Error: file not found"-->
@@ -373,8 +371,8 @@
<string name="progress_encrypting">chiffrement des données...</string>
<string name="progress_decrypting">déchiffrement des données...</string>
<string name="progress_preparing_signature">préparation de la signature...</string>
- <string name="progress_generating_signature">génération de la signature...</string>
<string name="progress_processing_signature">traitement de la signature...</string>
+ <string name="progress_generating_signature">génération de la signature...</string>
<string name="progress_verifying_signature">vérification de la signature...</string>
<string name="progress_signing">signature...</string>
<string name="progress_certifying">certification...</string>
@@ -386,15 +384,10 @@
<string name="progress_deleting">suppression des clefs...</string>
<string name="progress_con_saving">consolider : enregistrement dans le cache...</string>
<string name="progress_con_reimport">consolider : réimportation...</string>
- <string name="progress_verifying_keyserver_url">vérification du serveur de clefs...</string>
<string name="progress_starting_orbot">Démarrage d\'Orbot...</string>
<!--action strings-->
<string name="hint_cloud_search_hint">Chercher par nom, adresse courriel...</string>
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -424,14 +417,14 @@
<string name="help_about_version">Version :</string>
<!--Import-->
<string name="import_tab_keyserver">Serveur de clefs</string>
- <string name="import_tab_cloud">Rechercher dans le nuage</string>
+ <string name="import_tab_cloud">Recherche de clefs</string>
<string name="import_tab_direct">Fichier/presse-papiers</string>
<string name="import_tab_qr_code">Code QR/NFC</string>
<string name="import_import">Importer les clefs choisies</string>
- <string name="import_qr_code_wrong">Code QR incorrecte ! Veuillez réessayer !</string>
- <string name="import_qr_code_fp">L\'empreinte est malformée ou trop courte !</string>
+ <string name="import_qr_code_wrong">Le code QR est mal formé ! Veuillez ressayer !</string>
+ <string name="import_qr_code_fp">L\'empreinte est mal formée ou trop courte !</string>
<string name="import_qr_code_too_short_fingerprint">L\'empreinte est trop courte !</string>
- <string name="import_qr_code_button">Lire le code QR</string>
+ <string name="import_qr_code_button">Lire un code QR</string>
<string name="import_qr_code_text">Placez votre appareil photo au-dessus du code QR !</string>
<!--Import from URL-->
<string name="import_url_warn_no_search_parameter">Aucune demande de recherche n\'a été définie. Vous pouvez quand même effectuer une recherche manuelle sur le serveur de clefs.</string>
@@ -441,12 +434,12 @@
<string name="with_cancelled">, jusqu\'à l\'annulation</string>
<!--Import result toast-->
<plurals name="import_keys_added_and_updated_1">
- <item quantity="one">Clef importée avec succès</item>
+ <item quantity="one">Une clef importée avec succès</item>
<item quantity="other">%1$d clefs importées avec succès</item>
</plurals>
<plurals name="import_keys_added_and_updated_2">
- <item quantity="one">et mise à jour de la clef%2$s.</item>
- <item quantity="other">et mise à jour de %1$d clefs%2$s.</item>
+ <item quantity="one">et une clef%2$s mise à jour.</item>
+ <item quantity="other">et %1$d clefs%2$s mises à jour.</item>
</plurals>
<plurals name="import_keys_added">
<item quantity="one">Une clef%2$s importée avec succès.</item>
@@ -492,8 +485,8 @@
<string name="revoke_cancelled">Opération de révocation annulée.</string>
<!--Certify result toast-->
<plurals name="certify_keys_ok">
- <item quantity="one">Une key%2$s certifiée avec succès.</item>
- <item quantity="other">%1$d key%2$s certifiées avec succès.</item>
+ <item quantity="one">Clef%2$s confirmée avec succès</item>
+ <item quantity="other">%1$d clefs%2$s confirmées avec succès</item>
</plurals>
<plurals name="certify_keys_with_errors">
<item quantity="one">La certification a échoué !</item>
@@ -566,7 +559,10 @@
</plurals>
<string name="key_list_empty_text1">Aucune clef trouvée !</string>
<string name="key_list_filter_show_all">Montrer toutes les clefs</string>
- <string name="key_list_filter_show_certified">Montrer seulement les clefs certifiées</string>
+ <string name="key_list_filter_show_certified">Ne montrer que les clefs confirmées</string>
+ <string name="key_list_fab_qr_code">Lire un code QR</string>
+ <string name="key_list_fab_search">Recherche de clefs</string>
+ <string name="key_list_fab_import">Importer d\'un fichier</string>
<!--Key view-->
<string name="key_view_action_edit">Modifier la clef</string>
<string name="key_view_action_encrypt">Chiffrer un texte</string>
@@ -583,23 +579,16 @@
<string name="key_view_tab_keybase">Keybase.io</string>
<string name="user_id_info_revoked_title">Révoquée</string>
<string name="user_id_info_revoked_text">Cette identité a été révoquée par le propriétaire de la clef. Elle n\'est plus valide.</string>
- <string name="user_id_info_certified_title">Certifié</string>
- <string name="user_id_info_certified_text">Vous avez certifié cette identité.</string>
- <string name="user_id_info_uncertified_title">Non certifié</string>
- <string name="user_id_info_uncertified_text">Cette identité n\'a pas encore été certifiée. Vous ne pouvez pas être sûr que l\'identité correspond vraiment à une personne déterminée.</string>
+ <string name="user_id_info_certified_title">Confirmée</string>
+ <string name="user_id_info_certified_text">Vous avez confirmé l\'identité.</string>
+ <string name="user_id_info_uncertified_title">Non confirmée</string>
+ <string name="user_id_info_uncertified_text">Cette identité n\'a pas encore été confirmée. Vous ne pouvez pas être certain si l\'identité correspond vraiment à une personne spécifique.</string>
<string name="user_id_info_invalid_title">Invalide</string>
<string name="user_id_info_invalid_text">Quelque chose ne va pas avec cette identité !</string>
<!--Key trust-->
- <string name="key_trust_already_verified">Vous avez déjà confirmé cette clef !</string>
- <string name="key_trust_it_is_yours">C\'est une de vos clefs !</string>
- <string name="key_trust_maybe">Cette clef n\'est ni révoquée, ni expirée.\nVous ne l\'avez pas confirmée, mais vous pourriez décider de lui faire confiance.</string>
- <string name="key_trust_revoked">Cette clef a été révoquée par son propriétaire. Vous ne devriez pas lui faire confiance.</string>
- <string name="key_trust_expired">Cette clef est expirée. Vous ne devriez pas lui faire confiance.</string>
- <string name="key_trust_old_keys">Vous pourriez l\'utiliser pour déchiffrer un ancien message datant de la période de validité de la clef.</string>
- <string name="key_trust_no_cloud_evidence">Aucune preuve de fiabilité provenant du nuage pour cette clef.</string>
+ <string name="key_trust_no_cloud_evidence">Aucune preuve en provenance de l\'Internet sur la fiabilité de cette clef.</string>
<string name="key_trust_start_cloud_search">Lancer la recherche</string>
<string name="key_trust_results_prefix">Keybase.io offre des « preuves » affirmant que le propriétaire de cette clef : </string>
- <string name="key_trust_header_text">Note : les preuves de keybase.io sont une fonction expérimentales d\'OpenKeychain. Nous vous encourageons à lire des codes QR ou à échanger des clefs via NFC en plus de les confirmer.</string>
<!--keybase proof stuff-->
<string name="keybase_narrative_twitter">Publie sur Twitter en tant que %s</string>
<string name="keybase_narrative_github">Est connu sur GitHub en tant que %s</string>
@@ -647,7 +636,7 @@
<item>Changer l\'expiration</item>
<item>Révoquer la sous-clef</item>
<item>Dépouiller la sous-clef</item>
- <item>Déplacer la sous-clef vers la ClefYubi / carte à puce</item>
+ <item>Déplacer la sous-clef vers la Yubikey / carte à puce</item>
</string-array>
<string name="edit_key_new_subkey">nouvelle sous-clef</string>
<string name="edit_key_select_flag">Veuillez sélectionner au moins un drapeau !</string>
@@ -657,7 +646,7 @@
<string name="edit_key_error_bad_nfc_size">La taille de clef n\'est pas prise en charge par la carte à puce !</string>
<string name="edit_key_error_bad_nfc_stripped">Impossible de déplacer la clef vers la carte à puce (soit dépouillée, soit « dévier-vers-la-carte ») !</string>
<!--Create key-->
- <string name="create_key_upload">Synchroniser avec le nuage</string>
+ <string name="create_key_upload">Synchroniser avec l\'Internet</string>
<string name="create_key_empty">Ce champ est exigé</string>
<string name="create_key_passphrases_not_equal">Les mots de passe ne correspondent pas</string>
<string name="create_key_final_text">Vous avez saisie l\'identité suivante :</string>
@@ -673,12 +662,9 @@
<string name="create_key_add_email_text">Des adresses courriel supplémentaires sont aussi associées à cette clef et peuvent être utilisées pour des communications sécurisées.</string>
<string name="create_key_email_already_exists_text">L\'adresse courriel a déjà été ajoutée</string>
<string name="create_key_email_invalid_email">Le format de l\'adresse courriel est invalide</string>
- <string name="create_key_yubi_key_pin_text">Veuillez mémoriser le NIP. Il sera exigé pour une utilisation ultérieure de votre ClefYubi. Prenez si possible le NIP d\'admin. en note et stockez-le dans un endroit sûr</string>
<string name="create_key_yubi_key_pin">NIP</string>
<string name="create_key_yubi_key_admin_pin">NIP d\'admin.</string>
- <string name="create_key_yubi_key_pin_repeat_text">Veuillez saisir le NIP et le NIP d\'admin. pour continuer.</string>
<string name="create_key_yubi_key_pin_repeat">Répéter le NIP</string>
- <string name="create_key_yubi_key_admin_pin_repeat">Répéter le NIP d\'admin.</string>
<string name="create_key_yubi_key_pin_not_correct">NIP erroné !</string>
<!--View key-->
<string name="view_key_revoked">Révoquée : la clef ne doit plus être utilisée !</string>
@@ -686,12 +672,11 @@
<string name="view_key_expired_secret">Expirée : vous pouvez prolonger la validité de la clef en la modifiant !</string>
<string name="view_key_my_key">Ma clef</string>
<string name="view_key_verified">Clef confirmée</string>
- <string name="view_key_unverified">Non confirmée : lisez le code QR pour confirmer la clef !</string>
+ <string name="view_key_unverified">Non confirmée : lisez un code QR pour confirmer la clef !</string>
<string name="view_key_fragment_no_system_contact">&lt;aucun&gt;</string>
<!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Ajouter un serveur de clefs</string>
<string name="edit_keyserver_dialog_title">Modifier le serveur de clefs</string>
- <string name="add_keyserver_verified">Le serveur de clefs a été vérifié !</string>
<string name="add_keyserver_without_verification">Le serveur de clefs a été ajouté sans vérification.</string>
<string name="add_keyserver_invalid_url">URL invalide !</string>
<string name="add_keyserver_connection_failed">Échec de connexion au serveur de clefs. Veuillez vérifier l\'URL et votre connexion Internet.</string>
@@ -704,7 +689,6 @@
<string name="drawer_open">Ouvrir le tiroir de navigation</string>
<string name="drawer_close">Fermer le tiroir de navigation</string>
<string name="my_keys">Mes clefs</string>
- <string name="nav_backup">Sauvegarde</string>
<!--hints-->
<string name="encrypt_content_edit_text_hint">Saisir le texte</string>
<!--certs-->
@@ -754,7 +738,7 @@
<string name="msg_ip_master_flags_xxxa">Drapeaux maîtres : authentifier</string>
<string name="msg_ip_master_flags_xxxx">Drapeaux maîtres : aucun</string>
<string name="msg_ip_merge_public">Fusion des données importées dans le trousseau public existant</string>
- <string name="msg_ip_merge_secret">Fusion des données importées dans le trousseau public existant</string>
+ <string name="msg_ip_merge_secret">Fusion des données importées dans le trousseau secret existant</string>
<string name="msg_ip_subkey">Traitement de la sous-clef %s</string>
<string name="msg_ip_subkey_expired">La sous-clef a expiré le %s</string>
<string name="msg_ip_subkey_expires">La sous-clef expire le %s</string>
@@ -820,7 +804,7 @@
<string name="msg_is_importing_subkeys">Traitement des sous-clefs secrètes</string>
<string name="msg_is_error_io_exc">Erreur d\'encodage du trousseau</string>
<string name="msg_is_merge_public">Fusion des données importées dans le trousseau public existant</string>
- <string name="msg_is_merge_secret">Fusion des données importées dans le trousseau public existant</string>
+ <string name="msg_is_merge_secret">Fusion des données importées dans le trousseau secret existant</string>
<string name="msg_is_merge_special">Fusion des données du trousseau public dans les auto-certificats</string>
<string name="msg_is_pubring_generate">Génération du trousseau public à partir du trousseau secret</string>
<string name="msg_is_subkey_nonexistent">La sous-clef %s n\'est pas disponible dans la clef secrète</string>
@@ -837,7 +821,7 @@
<string name="msg_kc_error_v3">C\'est une clef OpenPGP version 3, qui a été déprécié et n\'est plus pris en charge !</string>
<string name="msg_kc_error_no_uid">Le trousseau n\'a pas d\'ID utilisateur valide !</string>
<string name="msg_kc_error_master_algo">La clef maîtresse utilise un algorithme (%s) inconnu ! </string>
- <string name="msg_kc_error_dup_key">La sous-clef %s se présente deux fois dans le trousseau. Le trousseau est mal formé, pas d\'importation ! </string>
+ <string name="msg_kc_error_dup_key">La sous-clef %s se présente deux fois dans le trousseau. Le trousseau est mal formé, pas d\'importation !</string>
<string name="msg_kc_master">Traitement de la clef maîtresse</string>
<string name="msg_kc_master_bad_type">Suppression du certificat de clef maîtresse de type inconnu (%s)</string>
<string name="msg_kc_master_bad_local">Suppression du certificat de clef maîtresse ayant le drapeau « local »</string>
@@ -921,7 +905,6 @@
<string name="msg_cr_error_no_user_id">Les trousseaux doivent être créés avec au moins un ID utilisateur !</string>
<string name="msg_cr_error_no_certify">La clef maîtresse doit avoir le drapeau « certifié » !</string>
<string name="msg_cr_error_null_expiry">L\'expiration ne peut pas être « pareille qu\'avant » à la création de la clef. C\'est une erreur du programme, veuillez remplir un rapport de bogue !</string>
- <string name="msg_cr_error_keysize_512">La taille de la clef doit être supérieure ou égale à 512 !</string>
<string name="msg_cr_error_no_curve">Aucune taille de clef n\'a été spécifiée ! C\'est une erreur de programmation, veuillez remplir un rapport de bogue !</string>
<string name="msg_cr_error_no_keysize">Aucune courbe elliptique n\'a été spécifiée ! C\'est une erreur de programmation, veuillez remplir un rapport de bogue !</string>
<string name="msg_cr_error_internal_pgp">Erreur interne OpenPGP !</string>
@@ -1032,7 +1015,7 @@
<string name="msg_pr_error_key_not_found">Clef introuvable !</string>
<string name="msg_pr_fetching">Obtention de la clef à modifier (%s)</string>
<string name="msg_pr_subkey_match">Promotion de la sous-clef : %s</string>
- <string name="msg_pr_subkey_nomatch">La sous-clef n\'est pas sur la ClefYubi : %s</string>
+ <string name="msg_pr_subkey_nomatch">La sous-clef n\'est pas sur la Yubikey : %s</string>
<string name="msg_pr_success">Clef promue avec succès</string>
<!--Other messages used in OperationLogs-->
<string name="msg_ek_error_dummy">Impossible de modifier un trousseau avec une clef maîtresse dépouillée !</string>
@@ -1085,8 +1068,6 @@
<string name="msg_dc_insecure_key">Clef non fiable : soit la longueur de donnée de RSA/DSA/ElGamal est trop courte ou la courbe/algorithme ECC est considérée comme non fiable ! Cela peut être dû à une application ancienne ou à une attaque.</string>
<!--Messages for VerifySignedLiteralData operation-->
<string name="msg_vl">Lancement de la vérification de la signature</string>
- <string name="msg_vl_error_no_siglist">Aucune liste de signatures dans les données littérales signées</string>
- <string name="msg_vl_error_wrong_key">Le message n\'est pas signé avec la bonne clef</string>
<string name="msg_vl_error_missing_literal">Aucune information utile dans les données littérales signées </string>
<string name="msg_vl_clear_meta_file">Nom de fichier : %s</string>
<string name="msg_vl_clear_meta_mime">Type MIME : %s</string>
@@ -1106,7 +1087,6 @@
<string name="msg_se_success">Opération de signature/chiffrement réussie</string>
<!--Messages for PgpSignEncrypt operation-->
<string name="msg_pse_asymmetric">Préparation des clefs publiques pour le chiffrement</string>
- <string name="msg_pse_clearsign_only">La signature de texte en clair n\'est pas prise en charge !</string>
<string name="msg_pse_compressing">Préparation de la compression</string>
<string name="msg_pse_encrypting">Chiffrement des données</string>
<string name="msg_pse_error_bad_passphrase">Mot de passe erroné !</string>
@@ -1162,38 +1142,15 @@
<string name="msg_import_fetch_error_decode">Erreur de décodage du trousseau récupéré !</string>
<string name="msg_import_fetch_error">La clef n\'a pas pu être récupérée ! (problèmes réseau ?)</string>
<string name="msg_import_fetch_keybase">Récupération en provenance du keybase.io : %s</string>
- <string name="msg_import_fetch_error_keyserver">Impossible de récupérer la clef sur les serveurs de clefs : %s</string>
<string name="msg_import_fetch_keyserver">Récupération en provenance du serveur de clefs : %s</string>
<string name="msg_import_fetch_keyserver_ok">Récupération de la clef est réussie !</string>
<string name="msg_import_keyserver">Utilisation du serveur de clefs %s</string>
- <string name="msg_import_fingerprint_error">L\'empreinte de clef récupérée ne correspond pas à celle attendu !</string>
- <string name="msg_import_fingerprint_ok">Vérification de l\'empreinte OK !</string>
<string name="msg_import_merge">Fusion des données récupérées</string>
<string name="msg_import_merge_error">Erreur de fusion des données récupérées !</string>
<string name="msg_import_error">Échec de l\'opération d\'importation !</string>
<string name="msg_import_error_io">Échec de l\'opération causé par une erreur d\'E/S !</string>
<string name="msg_import_partial">Opération d\'importation réussie, avec des erreurs !</string>
<string name="msg_import_success">Opération d\'importation réussie !</string>
- <plurals name="msg_export">
- <item quantity="one">Exportation d\'une clef</item>
- <item quantity="other">Exportation de %d clefs</item>
- </plurals>
- <string name="msg_export_file_name">Nom de fichier : %s</string>
- <string name="msg_export_all">Exportation de toutes les clefs</string>
- <string name="msg_export_public">Exportation de la clef publique %s</string>
- <string name="msg_export_upload_public">Téléversement de la clef publique %s</string>
- <string name="msg_export_secret">Exportation de la clef secrète %s</string>
- <string name="msg_export_error_no_file">Aucun nom de fichier spécifié !</string>
- <string name="msg_export_error_fopen">Erreur d\'ouverture du fichier !</string>
- <string name="msg_export_error_no_uri">Aucun URI spécifié !</string>
- <string name="msg_export_error_uri_open">Erreur d\'ouverture du flux de l\'URI !</string>
- <string name="msg_export_error_storage">Le stockage n\'est pas prêt pour l\'écriture !</string>
- <string name="msg_export_error_db">Erreur de base de données !</string>
- <string name="msg_export_error_io">Erreur d\'entrée/sortie !</string>
- <string name="msg_export_error_key">Erreur de prétraitement des données de la clef !</string>
- <string name="msg_export_error_upload">Échec de téléversement de la clef vers le serveur. Veuillez vérifier votre connexion Internet.</string>
- <string name="msg_export_success">Opération d\'exportation réussie !</string>
- <string name="msg_export_upload_success">Téléversement vers le serveur de clefs réussi</string>
<string name="msg_del_error_empty">Rien à supprimer !</string>
<string name="msg_del_error_multi_secret">Les clefs secrètes ne peuvent être supprimées qu\'individuellement !</string>
<plurals name="msg_del">
@@ -1216,6 +1173,25 @@
<string name="msg_revoke_key">Révocation de la clef %s</string>
<string name="msg_revoke_key_fail">Échec de révocation de la clef</string>
<string name="msg_revoke_ok">Clef révoquée avec succès</string>
+ <!--Linked Identity verification-->
+ <string name="msg_lv">Vérification de l\'identité reliée...</string>
+ <string name="msg_lv_match">Recherche de jeton</string>
+ <string name="msg_lv_match_error">Aucun jeton n\'a été trouvé dans la ressource !</string>
+ <string name="msg_lv_fp_ok">Empreinte OK</string>
+ <string name="msg_lv_fp_error">L\'empreinte ne correspond pas !</string>
+ <string name="msg_lv_error_twitter_auth">Erreur d\'obtention du jeton auth de Twitter !</string>
+ <string name="msg_lv_error_twitter_handle">Décalage de pseudo de compte Twitter en réponse !</string>
+ <string name="msg_lv_error_twitter_response">Réponse inattendue de l\'API Twitter !</string>
+ <string name="msg_lv_error_github_handle">Décalage de pseudo de compte GitHub en réponse !</string>
+ <string name="msg_lv_error_github_not_found">Le gist ne contient aucun fichier correspondant !</string>
+ <string name="msg_lv_fetch">Récupération de l\'URI \'%s\'</string>
+ <string name="msg_lv_fetch_redir">Suivi de la redirection vers \'%s\'</string>
+ <string name="msg_lv_fetch_ok">Récupérée avec succès (HTTP %s)</string>
+ <string name="msg_lv_fetch_error">Erreur de serveur (HTTP %s)</string>
+ <string name="msg_lv_fetch_error_url">L\'URI est mal formée !</string>
+ <string name="msg_lv_fetch_error_io">Erreur d\'E/S</string>
+ <string name="msg_lv_fetch_error_format">Erreur de format !</string>
+ <string name="msg_lv_fetch_error_nothing">Ressource introuvable !</string>
<string name="msg_acc_saved">Compte enregistré</string>
<string name="msg_download_success">Téléchargement réussi !</string>
<string name="msg_download_no_valid_keys">Aucune clef valide n\'a été trouvée dans le fichier/presse-papiers |</string>
@@ -1236,12 +1212,7 @@
<string name="msg_keybase_error_dns_fail">Échec de récupération de l\'enregistrement DNS TXT</string>
<string name="msg_keybase_error_specific">%s</string>
<string name="msg_keybase_error_msg_payload_mismatch">Le billet de preuve déchiffré ne correspond pas à la valeur attendue</string>
- <!--Messages for Export Log operation-->
- <string name="msg_export_log_start">Exportation du journal</string>
- <string name="msg_export_log_error_fopen">Erreur d\'ouverture du fichier !</string>
- <string name="msg_export_log_error_no_file">Aucun nom de fichier spécifié !</string>
- <string name="msg_export_log_error_writing">Erreur E/S d\'écriture vers le fichier !</string>
- <string name="msg_export_log_success">Journal exporté avec succès !</string>
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<string name="passp_cache_notif_click_to_clear">Toucher pour effacer les mots de passe.</string>
<plurals name="passp_cache_notif_n_keys">
@@ -1252,7 +1223,7 @@
<string name="passp_cache_notif_clear">Effacer les mots de passe</string>
<string name="passp_cache_notif_pwd">Mot de passe</string>
<!--Keyserver sync-->
- <string name="keyserver_sync_orbot_notif_title">Synchroniser à partir du nuage (Orbot exigé)</string>
+ <string name="keyserver_sync_orbot_notif_title">Synchroniser à partir des serveurs, Orbot exigé</string>
<string name="keyserver_sync_orbot_notif_msg">Toquer pour lancer Orbot</string>
<string name="keyserver_sync_orbot_notif_start">Lancer Orbot</string>
<string name="keyserver_sync_orbot_notif_ignore">Directe</string>
@@ -1260,10 +1231,10 @@
<string name="first_time_text1">Reprenez le contrôle de votre vie privée avec OpenKeychain |</string>
<string name="first_time_create_key">Créer ma clef</string>
<string name="first_time_import_key">Importer la clef d\'un fichier</string>
- <string name="first_time_yubikey">Utiliser le NEO de la ClefYubi</string>
+ <string name="first_time_yubikey">Utiliser la Yubikey NEO</string>
<string name="first_time_skip">Ignorer le paramétrage</string>
- <string name="first_time_blank_yubikey">Voulez-vous utiliser cette ClefYubi NEO vide avec OpenKeychain ?\n\nVeuillez retirer la ClefYubi maintenant, vous serez informé quand elle sera requise de nouveau !</string>
- <string name="first_time_blank_yubikey_yes">Utiliser cette ClefYubi</string>
+ <string name="first_time_blank_yubikey">Voulez-vous utiliser cette Yubikey NEO vide avec OpenKeychain ?\n\nVeuillez retirer la Yubikey maintenant, vous serez informé quand elle sera requise de nouveau !</string>
+ <string name="first_time_blank_yubikey_yes">Utiliser cette Yubikey</string>
<string name="backup_text">Les sauvegardes incluant vos propres clefs ne doivent jamais être partagées avec d\'autres personnes !</string>
<string name="backup_all">Toutes les clefs + vos propres clefs</string>
<string name="backup_public_keys">Toutes les clefs</string>
@@ -1272,13 +1243,11 @@
<string name="section_certifier_id">Certificateur</string>
<string name="section_cert">Détails du certificat</string>
<string name="label_user_id">identité</string>
- <string name="unknown_uid">&lt;inconnu&gt;</string>
+ <string name="unknown_uid"><![CDATA[<unknown>]]></string>
<string name="empty_certs">Aucun certificat pour cette clef</string>
<string name="certs_text">Seuls les auto-certificats et les certificats validés créés avec vos clefs sont affichés ici.</string>
<string name="section_uids_to_certify">Identités pour</string>
<string name="certify_text">Les clefs que vous importez contiennent des « identités » : des noms et des adresses courriel. Pour la confirmation, choisissez exactement celles qui correspondent à ce que vous attendiez.</string>
- <string name="certify_fingerprint_text">Comparez l\'empreinte affichée, caractère par caractère, à celle affichée sur l\'appareil de l\'autre personne.</string>
- <string name="certify_fingerprint_text2">Est-ce que les empreintes affichées correspondent ?</string>
<string name="label_revocation">Raison de la révocation</string>
<string name="label_cert_type">Type</string>
<string name="error_key_not_found">Clef introuvable !</string>
@@ -1338,31 +1307,30 @@
<string name="button_bind_key">Relier la clef</string>
<string name="yubikey_serno">No de série : %s</string>
<string name="yubikey_key_holder">Détenteur de la clef :</string>
- <string name="yubikey_key_holder_not_set">Détenteur de la clef : &lt;not set&gt;</string>
- <string name="yubikey_status_bound">La ClefYubi correspond et est reliée à la clef</string>
- <string name="yubikey_status_unbound">La ClefYubi correspond et peut être reliée à la clef</string>
- <string name="yubikey_status_partly">La ClefYubi correspond et est partiellement reliée à la clef</string>
- <string name="yubikey_create">Tenez la ClefYubi contre le dos de votre appareil.</string>
+ <string name="yubikey_key_holder_not_set"><![CDATA[Détenteur de la clef : <not set>]]></string>
+ <string name="yubikey_status_bound">La Yubikey correspond et est reliée à la clef</string>
+ <string name="yubikey_status_unbound">La Yubikey correspond et peut être reliée à la clef</string>
+ <string name="yubikey_status_partly">La Yubikey correspond et est partiellement reliée à la clef</string>
+ <string name="yubikey_create">Tenez la Yubikey contre le dos de votre appareil.</string>
<string name="btn_import">Importer</string>
- <string name="snack_yubi_other">Une clef différente est stockée sur la ClefYubi !</string>
+ <string name="snack_yubi_other">Une clef différente est stockée sur la Yubikey !</string>
<string name="error_nfc">Erreur NFC ; %s</string>
<plurals name="error_pin">
<item quantity="one">NIP erroné !\nil reste %d essai.</item>
<item quantity="other">NIP erroné !\nil reste %d essais.</item>
</plurals>
- <string name="error_nfc_terminated">La ClefYubi est en état de fin d\'opération.</string>
+ <string name="error_nfc_terminated">La Yubikey est en état de fin d\'opération.</string>
<string name="error_nfc_wrong_length">Le NIP saisi est trop court. Les NIP comportent au moins 6 chiffres.</string>
<string name="error_nfc_conditions_not_satisfied">Les conditions d\'utilisation ne sont pas satisfaites.</string>
<string name="error_nfc_security_not_satisfied">L\'état de sécurité n\'est pas satisfait.</string>
<string name="error_nfc_authentication_blocked">NIP bloqué après trop d\'essais.</string>
<string name="error_nfc_data_not_found">Clef ou objet introuvable.</string>
<string name="error_nfc_unknown">Erreur inconnue</string>
- <string name="error_nfc_bad_data">La ClefYubi a signalé des données invalides.</string>
- <string name="error_nfc_chaining_error">La ClefYubi attendait la dernière commande d\'une chaîne.</string>
- <string name="error_nfc_header">La ClefYubi a signalé %s bytes invalides.</string>
- <string name="error_nfc_tag_lost">La ClefYubi a été retirée trop tôt. Conservez la ClefYubi contre le dos jusqu\'à la fin de l\'opération.</string>
+ <string name="error_nfc_bad_data">La Yubikey a signalé des données invalides.</string>
+ <string name="error_nfc_chaining_error">La Yubikey attendait la dernière commande d\'une chaîne.</string>
+ <string name="error_nfc_header">La Yubikey a signalé %s bytes invalides.</string>
+ <string name="error_nfc_tag_lost">La Yubikey a été retirée trop tôt. Gardez la Yubikey contre le dos jusqu\'à la fin de l\'opération.</string>
<string name="error_nfc_try_again">Ressayer</string>
- <string name="error_pin_nodefault">Le NIP par défaut a été rejeté !</string>
<string name="error_temp_file">Erreur de création du fichier temporaire.</string>
<string name="btn_delete_original">Supprimer le fichier original</string>
<string name="snack_encrypt_filenames_on">Les noms de fichiers <b>sont</b> chiffrés.</string>
@@ -1374,8 +1342,8 @@
<string name="error_loading_keys">Erreur de chargement des clefs !</string>
<string name="error_empty_log">(erreur, journal vide)</string>
<string name="error_reading_text">Impossible de lire l\'entrée à déchiffrer !</string>
- <string name="filename_unknown">&lt;aucun nom de fichier&gt;</string>
- <string name="filename_unknown_text">&lt;données texte en clair &gt;</string>
+ <string name="filename_unknown">Nom de fichier inconnu (cliquer pour ouvrir)</string>
+ <string name="filename_unknown_text">Texte (cliquer pour montrer)</string>
<string name="intent_show">Montrer le contenu signé/chiffré</string>
<string name="view_internal">Visualiser dans OpenKeychain</string>
<string name="error_preparing_data">Erreur de préparation des données !</string>
@@ -1387,8 +1355,65 @@
<string name="file_delete_none">Aucun fichier supprimé (déjà supprimé ?)</string>
<string name="file_delete_exception">Impossible de supprimer le fichier original !</string>
<string name="error_clipboard_empty">Le presse-papiers est vide !</string>
- <string name="error_clipboard_copy">Erreur de copie des données vers le presse-papiers !</string>
+ <string name="error_clipboard_copy">Erreur de copie des données dans le presse-papiers !</string>
<string name="error_scan_fp">Erreur de numérisation de l\'empreinte !</string>
<string name="error_scan_match">Les empreintes ne correspondent pas !</string>
<string name="error_expiry_past">La date d\'expiration est dans le passé !</string>
+ <string name="linked_create_https_1_1">En créant une identité reliée de ce type, vous pouvez relier votre clef à un site Web que vous contrôlez.</string>
+ <string name="linked_create_https_1_2">Pour ce faire, vous publiez un fichier texte sur ce site Web et créez ensuite une identité reliée à ce fichier.</string>
+ <string name="linked_create_https_1_3">Veuillez saisir l\'URL d\'un site où vous pouvez disposer un fichier texte comme preuve. Veuillez prendre note que votre serveur doit prendre https en charge et avoir un certificat TLS valide !</string>
+ <string name="linked_create_https_1_4">Exemple : https://example.com/pgpkey.txt</string>
+ <string name="linked_create_https_created">Le fichier de preuve a été créé. La prochaine étape est de l\'enregistrer et de le téléverser vers l\'URI indiquée :</string>
+ <string name="linked_create_https_2_1">Un fichier de preuve a été créé pour cette URI :</string>
+ <string name="linked_create_https_2_2">La prochaine étape est d\'enregistrer et de téléverser ce fichier.</string>
+ <string name="linked_create_https_2_3">Assurez-vous que le fichier est atteignable à la bonne URI, puis vérifiez le tout.</string>
+ <string name="linked_create_https_2_4">Suite à une vérification probante, appuyez sur le bouton Terminer pour ajouter l\'identité reliée à votre trousseau et compléter le processus.</string>
+ <string name="linked_create_twitter_1_1">En créant une identité reliée de ce type, vous pouvez relier votre clef à un compte Twitter que vous contrôlez.</string>
+ <string name="linked_create_twitter_1_2">Pour ce faire, vous publiez un gazouillis particulier sur votre fil d\'actualité et créez ensuite une identité reliée à ce gazouillis.</string>
+ <string name="linked_create_twitter_1_3">Veuillez saisir votre nom d\'utilisateur Twitter pour continuer.</string>
+ <string name="linked_create_twitter_handle">Pseudo Twitter</string>
+ <string name="linked_create_twitter_2_1">Cliquer sur l\'un des boutons pour twitter le message !</string>
+ <string name="linked_create_twitter_2_2">Vous pouvez modifier le gazouillis avant de le publier tant que le texte entre parenthèses reste inchangé.</string>
+ <string name="linked_create_twitter_2_3">Une fois que votre gazouillis est publié comme &lt;b&gt;@%s&lt;/b&gt;, cliquez sur le bouton Vérifier pour le chercher dans votre fil d\'actualité.</string>
+ <string name="linked_create_twitter_2_4">Suite à une vérification probante, appuyez sur le bouton Terminer pour ajouter l\'identité reliée à votre trousseau et compléter le processus.</string>
+ <string name="linked_create_verify">Vérifier</string>
+ <string name="linked_text_clipboard">La texte a été copié dans le presse-papiers</string>
+ <string name="linked_verified_https">Le lien entre le site Web et la clef a été vérifié de façon sécuritaire. <b>Si vous pensez que le site est authentique</b>, confirmez cette vérification avec votre clef.</string>
+ <string name="linked_verified_github">Le lien entre ce compte GitHub et la clef a été vérifié de façon sécuritaire. <b>Si vous pensez que le compte est authentique</b>, confirmez cette vérification avec votre clef.</string>
+ <string name="linked_verified_dns">Le lien entre ce nom de domaine et la clef a été vérifié de façon sécuritaire. <b>Si vous pensez que le nom de domaine est authentique</b>, confirmez cette vérification avec votre clef.</string>
+ <string name="linked_verified_twitter">Le lien entre ce compte Twitter et la clef a été vérifié de façon sécuritaire. <b>Si vous pensez que le compte est authentique</b>, confirmez cette vérification avec votre clef.</string>
+ <string name="linked_verified_secret_https">Tout semble en règle.</string>
+ <string name="linked_verified_secret_github">Tout semble en règle.</string>
+ <string name="linked_verified_secret_dns">Tout semble en règle.</string>
+ <string name="linked_verified_secret_twitter">Tout semble en règle.</string>
+ <plurals name="linked_id_expand">
+ <item quantity="one">Il y a un autre type d\'identité inconnu</item>
+ <item quantity="other">Il y a %d autres types d\'identité inconnus</item>
+ </plurals>
+ <!--Other Linked Identity strings-->
+ <string name="linked_select_2">Veuillez choisir un type :</string>
+ <string name="linked_id_generic_text">Ce fichier revendique la propriété de la clef OpenPGP ayant %2$s pour ID long.\n\nJeton pour preuve :\n%1$s</string>
+ <string name="linked_id_github_text">Ce gist confirme l\'identité reliée se trouvant dans ma clef OpenPGP et le relie à ce compte GitHub.\n\nJeton pour preuve :\n%1$s</string>
+ <string name="linked_verifying">Vérification...</string>
+ <string name="linked_verify_success">Vérifiée !</string>
+ <string name="linked_verify_error">Erreur de vérification !</string>
+ <string name="linked_verify_pending">Pas encore vérifiée</string>
+ <string name="linked_need_verify">La ressource doit être vérifiée avant que vous ne puissiez continuer !</string>
+ <string name="menu_linked_add_identity">Relier au compte</string>
+ <string name="section_linked_identities">Identités reliées</string>
+ <string name="btn_finish">Terminer</string>
+ <string name="linked_title_https">Site Web (HTTPS)</string>
+ <string name="linked_title_dns">Nom de domaine (DNS)</string>
+ <string name="linked_title_github">GitHub</string>
+ <string name="linked_title_twitter">Twitter</string>
+ <string name="card_linked_identity">Identité reliée</string>
+ <string name="linked_button_verify">Vérifier</string>
+ <string name="linked_button_retry">Ressayer</string>
+ <string name="linked_button_confirm">Confirmer</string>
+ <string name="linked_button_view">Visualiser</string>
+ <string name="linked_text_verifying">Vérification...</string>
+ <string name="linked_text_error">Erreur</string>
+ <string name="linked_text_confirming">Confirmation...</string>
+ <string name="linked_ids_more_unknown">%d autres types d\'identité inconnus</string>
+ <string name="title_linked_id_create">Créer l\'identité reliée</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-it/strings.xml b/OpenKeychain/src/main/res/values-it/strings.xml
index 9f58dc3ba..1b8d2729a 100644
--- a/OpenKeychain/src/main/res/values-it/strings.xml
+++ b/OpenKeychain/src/main/res/values-it/strings.xml
@@ -9,6 +9,7 @@
<string name="title_decrypt">Decodifica</string>
<string name="title_add_subkey">Aggiungi Sottochiave</string>
<string name="title_edit_key">Modifica Chiave</string>
+ <string name="title_linked_create">Creare un\'identità collegata</string>
<string name="title_preferences">Impostazioni</string>
<string name="title_api_registered_apps">Apps</string>
<string name="title_key_server_preference">Server chiavi OpenPGP</string>
@@ -31,17 +32,20 @@
<string name="title_exchange_keys">Scambia le chiavi</string>
<string name="title_advanced_key_info">Informazioni avanzate</string>
<string name="title_delete_secret_key">Cancellare la TUA chiave \'%s\'?</string>
- <string name="title_export_log">Esporta log</string>
<string name="title_manage_my_keys">Gestisci le mie chiavi</string>
<!--section-->
<string name="section_user_ids">Identità</string>
<string name="section_yubikey">YubiKey</string>
<string name="section_should_you_trust">Ci si potrà fidare di questa chiave?</string>
<string name="section_proof_details">Verifica prova</string>
- <string name="section_cloud_evidence">Prova dalla cloud</string>
<string name="section_keys">Sottochiavi</string>
- <string name="section_cloud_search">Ricerca</string>
- <string name="section_passphrase_cache">Trattamento Password/PIN</string>
+ <string name="section_cloud_search">Ricerca chiave</string>
+ <string name="section_cloud_search_summary">Server chiavi, keybase.io</string>
+ <string name="section_passphrase_cache">Password e PIN</string>
+ <string name="section_proxy_settings">Rete anonimata</string>
+ <string name="section_gui">Interfaccia</string>
+ <string name="section_sync_settings">Sincronizzazione</string>
+ <string name="section_experimental_features">Caratteristiche sperimentali</string>
<string name="section_certify">Conferma</string>
<string name="section_actions">Azioni</string>
<string name="section_share_key">Chiave</string>
@@ -67,12 +71,9 @@
<string name="btn_back">Precedente</string>
<string name="btn_no">No</string>
<string name="btn_match">Impronte digitali ugali</string>
- <string name="btn_share_encrypted_signed">Codifica e condividi testo</string>
- <string name="btn_copy_encrypted_signed">Codifica e copia testo</string>
<string name="btn_view_cert_key">Mostra chiave di certificazione</string>
<string name="btn_create_key">Crea chiave</string>
<string name="btn_add_files">Aggiungi file(s)</string>
- <string name="btn_share_decrypted_text">Condividi testo decifrato</string>
<string name="btn_copy_decrypted_text">Copia testo decifrato</string>
<string name="btn_decrypt_clipboard">Leggi dagli appunti</string>
<string name="btn_decrypt_files">Seleziona input file</string>
@@ -96,8 +97,6 @@
<string name="menu_export_all_keys">Esporta tutte le chiavi</string>
<string name="menu_update_all_keys">Aggiorna tutte le chiavi</string>
<string name="menu_advanced">Informazioni avanzate</string>
- <string name="menu_certify_fingerprint">Confermare tramite il confronto delle impronte digitali</string>
- <string name="menu_export_log">Esporta log</string>
<string name="menu_keyserver_add">Aggiungi</string>
<!--label-->
<string name="label_message">Testo</string>
@@ -114,9 +113,7 @@
<string name="label_file_ascii_armor">Abilita Armatura ASCII</string>
<string name="label_write_version_header">Fai sapere agli altri che utilizzi OpenKeychain</string>
<string name="label_write_version_header_summary">Scrive \'OpenKeychain v2.7\' nelle firme OpenPGP, testi cifrati e chiavi esportate</string>
- <string name="label_use_default_yubikey_pin">Utilizza il PIN predefinito di YubiKey</string>
<string name="label_use_num_keypad_for_yubikey_pin">Utilizza la tastiera numerica per il PIN di YubiKey</string>
- <string name="label_label_use_default_yubikey_pin_summary">Usa PIN predefinito (123456) per accedere YubiKeys tramite NFC</string>
<string name="label_to">Codifica per:</string>
<string name="label_delete_after_encryption">Elimina file dopo la codifica</string>
<string name="label_delete_after_decryption">Elimina dopo la decodifica</string>
@@ -139,7 +136,6 @@
<string name="label_name">Nome</string>
<string name="label_comment">Commento</string>
<string name="label_email">Email</string>
- <string name="label_send_key">Sincronizza con il cloud</string>
<string name="label_fingerprint">Impronta</string>
<string name="expiry_date_dialog_title">Impostare la data di scadenza</string>
<string name="label_keyservers_title">Server chiavi</string>
@@ -149,34 +145,29 @@
<string name="label_enable_compression">Abilitare compressione</string>
<string name="label_encrypt_filenames">Codifica nome dei file</string>
<string name="label_hidden_recipients">Nascondi destinatari</string>
- <string name="label_verify_keyserver">Verificare server chiavi</string>
- <string name="label_enter_keyserver_url">Inserisci URL server chiavi</string>
<string name="label_keyserver_dialog_delete">Cancella server chiavi</string>
<string name="pref_keyserver">Server chiavi OpenPGP</string>
<string name="pref_keyserver_summary">Cerca chiavi su server chiavi OpenPGP selezionati (protocollo HKP)</string>
<string name="pref_keybase">keybase.io</string>
<string name="pref_keybase_summary">Ricerca chiavi su keybase.io</string>
<!--label shown in Android settings under the OpenKeychain account-->
+ <string name="label_experimental_settings_desc_title">Attenzione</string>
<!--Proxy Preferences-->
<string name="pref_proxy_type_title">Tipo proxy</string>
<!--proxy type choices and values-->
<string name="pref_proxy_type_choice_http">HTTP</string>
<string name="pref_proxy_type_choice_socks">SOCKS</string>
<!--OrbotHelper strings-->
- <string name="orbot_ignore_tor">Non usare Tor</string>
<!--InstallDialogFragment strings-->
<string name="orbot_install_dialog_title">Installa Orbot per usare Tor?</string>
<string name="orbot_install_dialog_install">Installa</string>
<string name="orbot_install_dialog_content">Orbot deve essere installato e attivato per fare attraversare il traffico dei dati tramite proxy. Vuoi installare Orbot?</string>
<string name="orbot_install_dialog_cancel">Annulla</string>
- <string name="orbot_install_dialog_ignore_tor">Non usare Tor</string>
<!--StartOrbotDialogFragment strings-->
<string name="orbot_start_dialog_title">Attivare Orbot?</string>
<string name="orbot_start_btn">Attivare Orbot</string>
<string name="orbot_start_dialog_start">Attivare Orbot</string>
<string name="orbot_start_dialog_cancel">Annulla</string>
- <string name="user_id_no_name">&lt;nessun nome&gt;</string>
- <string name="none">&lt;nessuno&gt;</string>
<plurals name="n_keys">
<item quantity="one">1 chiave</item>
<item quantity="other">%d chiavi</item>
@@ -218,7 +209,6 @@
<string name="no_filemanager_installed">Nessun gestore file compatibile installato.</string>
<string name="passphrases_do_not_match">Le password non corrispondono.</string>
<string name="passphrase_must_not_be_empty">Si prega di inserire una password.</string>
- <string name="passphrase_for_symmetric_encryption">Codifica Simmetrica.</string>
<string name="passphrase_for">Inserisci la password per \'%s\'</string>
<string name="pin_for">Inserisci il PIN per \'%s\'</string>
<string name="yubikey_pin_for">Inserisci il PIN per accedere a YubiKey con \'%s\'</string>
@@ -233,7 +223,6 @@
<string name="specify_file_to_encrypt_to">Per favore specifica il file da codificare entro.\nATTENZIONE: Il file sarà sovrascritto se esistente.</string>
<string name="specify_file_to_decrypt_to">Per favore specifica il file da decifrare entro.\nATTENZIONE: Il file sarà sovrascritto se esistente.</string>
<string name="key_deletion_confirmation_multi">Vuoi veramente eliminare tutte le chiavi selezionate?</string>
- <string name="secret_key_deletion_confirmation">Dopo la cancellazione non sarai in grado di leggere i messaggi cifrati con questa chiave e perderai tutte le conferme principali fatti con essa!</string>
<string name="public_key_deletetion_confirmation">Elimnina chiave \'%s\'?</string>
<string name="also_export_secret_keys">Esporta anche chiave segreta</string>
<string name="reinstall_openkeychain">Hai riscontrato un bug noto con Android. Si prega di reinstallare OpenKeychain se vuoi collegare i tuoi contatti con le chiavi.</string>
@@ -242,7 +231,6 @@
<string name="no_keys_exported">Nessuna chiave esportata.</string>
<string name="key_creation_el_gamal_info">Nota: supporto sottochiavi solo per ElGamal.</string>
<string name="key_not_found">Impossibile trovare la chiave %08X.</string>
- <string name="specify_file_to_export_log_to">Per favore specifica il file da esportare entro.\nATTENZIONE: Il file sarà sovrascritto se esistente.</string>
<plurals name="bad_keys_encountered">
<item quantity="one">%d chiave segreta corrotta ignorata. Tra l\'altro hai esportato con l\'opzione\n --export-secret-subkeys\nAssicurati di esportare con\n --export-secret-keys\ninvece.</item>
<item quantity="other">%d chiavi segrete corrotte ignorate. Tra l\'altro hai esportato con l\'opzione\n --export-secret-subkeys\nAssicurati di esportare con\n --export-secret-keys\ninvece.</item>
@@ -252,7 +240,6 @@
<string name="key_copied_to_clipboard">Chiave copiata negli appunti!</string>
<string name="fingerprint_copied_to_clipboard">Impronta copiata negli appunti!</string>
<string name="select_key_to_certify">Per favore seleziona una chiave da utilizzare per la conferma!</string>
- <string name="key_too_big_for_sharing">Chiave troppo grande per essere condivisa in questo modo!</string>
<string name="text_copied_to_clipboard">Il testo è stato copiato sulla lavagna!</string>
<!--errors
no punctuation, all lowercase,
@@ -332,8 +319,8 @@
<string name="progress_encrypting">codifica dati...</string>
<string name="progress_decrypting">decodifica dati...</string>
<string name="progress_preparing_signature">preparazione firma...</string>
- <string name="progress_generating_signature">generazione firma...</string>
<string name="progress_processing_signature">elaborazione firma...</string>
+ <string name="progress_generating_signature">generazione firma...</string>
<string name="progress_verifying_signature">verifica firma...</string>
<string name="progress_signing">firma...</string>
<string name="progress_certifying">certificazione...</string>
@@ -347,10 +334,6 @@
<string name="progress_con_reimport">consolidazione: reimportazione...</string>
<!--action strings-->
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -380,7 +363,6 @@
<string name="help_about_version">Versione:</string>
<!--Import-->
<string name="import_tab_keyserver">Server delle chiavi</string>
- <string name="import_tab_cloud">Ricerca Cloud</string>
<string name="import_tab_direct">File/Appunti</string>
<string name="import_tab_qr_code">Codice QR/NFC</string>
<string name="import_import">Importa chiavi selezionate</string>
@@ -392,14 +374,6 @@
<string name="with_warnings">, con avvisi</string>
<string name="with_cancelled">, fino all\'annullamento</string>
<!--Import result toast-->
- <plurals name="import_keys_added_and_updated_1">
- <item quantity="one">Chiave importata correttamente.</item>
- <item quantity="other">%1$d chiavi importate correttamente.</item>
- </plurals>
- <plurals name="import_keys_added_and_updated_2">
- <item quantity="one">e chiave%2$s aggiornata.</item>
- <item quantity="other">e aggiornate %1$d chiavi%2$s.</item>
- </plurals>
<plurals name="import_keys_added">
<item quantity="one">Chiave%2$s importata correttamente.</item>
<item quantity="other">%1$d chiavi%2$s importate correttamente.</item>
@@ -465,7 +439,6 @@ Permetti accesso?\n\nATTENZIONE: Se non sai perche\' questo schermata e\' appars
</plurals>
<string name="key_list_empty_text1">Nessuna chiave trovata!</string>
<string name="key_list_filter_show_all">Mostra tutte le chiavi</string>
- <string name="key_list_filter_show_certified">Mostra solo le chiavi certificate</string>
<!--Key view-->
<string name="key_view_action_edit">Modifica chiave</string>
<string name="key_view_action_encrypt">Codifica Testo</string>
@@ -480,10 +453,6 @@ Permetti accesso?\n\nATTENZIONE: Se non sai perche\' questo schermata e\' appars
<string name="key_view_tab_certs">Certificati</string>
<string name="user_id_info_revoked_title">Revocato</string>
<string name="user_id_info_revoked_text">Questa identità è stata revocata dal suo proprietario. Non è più valida.</string>
- <string name="user_id_info_certified_title">Certificato</string>
- <string name="user_id_info_certified_text">Questa identità è stata certificata da te.</string>
- <string name="user_id_info_uncertified_title">Non certificato</string>
- <string name="user_id_info_uncertified_text">Questa identità non è stata ancora certificata. Non puoi esser sicuro che l\'identità corrisponda veramente ad una specifica persona.</string>
<string name="user_id_info_invalid_title">Non valido</string>
<string name="user_id_info_invalid_text">C\'è qualcosa che non va con questa identità!</string>
<!--Key trust-->
@@ -658,7 +627,6 @@ Permetti accesso?\n\nATTENZIONE: Se non sai perche\' questo schermata e\' appars
<string name="msg_cr_error_no_master">Nessuna opzione della chiave principale specificata!</string>
<string name="msg_cr_error_no_certify">La chiave principale deve avere la caratteristica di certificazione!</string>
<string name="msg_cr_error_null_expiry">La data di scadenza non può essere \'come prima\' sulla creazione di chiavi. Questo è un errore di programmazione, si prega di inviare una segnalazione di bug!</string>
- <string name="msg_cr_error_keysize_512">La grandezza della chiave deve essere di 512bit o maggiore</string>
<string name="msg_cr_error_no_keysize">Nessuna curva ellittica specificata! Questo è un errore di programmazione, per favore invia una segnalazione!</string>
<!--modifySecretKeyRing-->
<string name="msg_mr">Modifica del portachiavi %s</string>
@@ -733,6 +701,7 @@ Permetti accesso?\n\nATTENZIONE: Se non sai perche\' questo schermata e\' appars
<string name="msg_crt_warn_not_found">Chiave non trovata!</string>
<string name="msg_crt_upload_success">Chiave caricata con successo sul server</string>
<string name="msg_del_error_empty">Niente da cancellare!</string>
+ <!--Linked Identity verification-->
<string name="msg_acc_saved">Account salvato</string>
<string name="msg_download_no_pgp_parts">DA FARE: plurali!</string>
<plurals name="error_import_non_pgp_part">
@@ -740,7 +709,7 @@ Permetti accesso?\n\nATTENZIONE: Se non sai perche\' questo schermata e\' appars
<item quantity="other">parti del file caricato sono oggetti OpenPGP validi, ma non chavi OpenPGP</item>
</plurals>
<!--Messages for Keybase Verification operation-->
- <!--Messages for Export Log operation-->
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<!--Keyserver sync-->
<!--First Time-->
@@ -750,7 +719,6 @@ Permetti accesso?\n\nATTENZIONE: Se non sai perche\' questo schermata e\' appars
<string name="section_certifier_id">Certificatore</string>
<string name="section_cert">Dettagli Certificato</string>
<string name="label_user_id">Identit</string>
- <string name="unknown_uid">&lt;sconosciuto&gt;</string>
<string name="empty_certs">Nessun certificato per questa chiave</string>
<string name="label_revocation">Ragione della Revoca</string>
<string name="label_cert_type">Tipo</string>
@@ -772,4 +740,5 @@ Permetti accesso?\n\nATTENZIONE: Se non sai perche\' questo schermata e\' appars
<!--<string name="enter_passphrase_twice">Enter password twice</string>-->
<!--<string name="nfc_text">Please place a NFC tag near your device</string>-->
<string name="file_saved">File salvato!</string>
+ <!--Other Linked Identity strings-->
</resources>
diff --git a/OpenKeychain/src/main/res/values-ja/strings.xml b/OpenKeychain/src/main/res/values-ja/strings.xml
index 6f735b35b..a2e68ac66 100644
--- a/OpenKeychain/src/main/res/values-ja/strings.xml
+++ b/OpenKeychain/src/main/res/values-ja/strings.xml
@@ -9,6 +9,7 @@
<string name="title_decrypt">復号化</string>
<string name="title_add_subkey">副鍵の追加</string>
<string name="title_edit_key">鍵の編集</string>
+ <string name="title_linked_create">リンクしたユーザIDを作成</string>
<string name="title_preferences">設定</string>
<string name="title_api_registered_apps">アプリ</string>
<string name="title_key_server_preference">OpenPGP鍵サーバ</string>
@@ -24,6 +25,7 @@
<string name="title_export_keys">鍵のバックアップ</string>
<string name="title_key_not_found">鍵が見当りません</string>
<string name="title_send_key">鍵サーバへアップロード</string>
+ <string name="title_backup">バックアップ鍵</string>
<string name="title_certify_key">鍵の確認</string>
<string name="title_key_details">鍵の概要</string>
<string name="title_help">ヘルプ</string>
@@ -31,26 +33,31 @@
<string name="title_exchange_keys">鍵の交換</string>
<string name="title_advanced_key_info">拡張情報</string>
<string name="title_delete_secret_key">あなたの鍵 \'%s\' を削除しますか?</string>
- <string name="title_export_log">エクスポートログ</string>
<string name="title_manage_my_keys">自分の鍵の管理</string>
<!--section-->
<string name="section_user_ids">ユーザID</string>
<string name="section_yubikey">YubiKey</string>
<string name="section_linked_system_contact">リンクしているシステムの連絡先</string>
+ <string name="section_keybase_proofs">Keybase.io 検証</string>
<string name="section_should_you_trust">この鍵を信頼しますか?</string>
<string name="section_proof_details">証明検証</string>
- <string name="section_cloud_evidence">クラウドからの証明</string>
<string name="section_keys">副鍵</string>
- <string name="section_cloud_search">クラウド検索</string>
- <string name="section_passphrase_cache">パスワード/PINの取り扱い</string>
- <string name="section_proxy_settings">プロキシの設定</string>
+ <string name="section_cloud_search">鍵検索</string>
+ <string name="section_cloud_search_summary">鍵サーバ, keybase.io</string>
+ <string name="section_passphrase_cache">パスワードとPIN</string>
+ <string name="section_passphrase_cache_summary">取り扱い、ユーザインタフェース、時間を忘れない</string>
+ <string name="section_proxy_settings">ネットワーク匿名性</string>
+ <string name="section_proxy_settings_summary">Tor、Proxyの設定</string>
<string name="section_gui">インタフェース</string>
- <string name="section_sync_settings">同期設定</string>
+ <string name="section_sync_settings">同期</string>
+ <string name="section_sync_settings_summary">鍵の自動アップデートと連絡先のリンク</string>
+ <string name="section_experimental_features">実験的機能</string>
<string name="section_certify">確認</string>
<string name="section_actions">アクション</string>
<string name="section_share_key">鍵</string>
<string name="section_key_server">鍵サーバ</string>
<string name="section_fingerprint">指紋</string>
+ <string name="section_phrases">語句</string>
<string name="section_encrypt">暗号化</string>
<string name="section_decrypt">復号 / 検証</string>
<string name="section_current_expiry">現在の期限</string>
@@ -71,12 +78,14 @@
<string name="btn_back">戻る</string>
<string name="btn_no">なし</string>
<string name="btn_match">指紋一致</string>
- <string name="btn_share_encrypted_signed">暗号化してテキストを共有</string>
- <string name="btn_copy_encrypted_signed">暗号化してテキストをコピー</string>
+ <string name="btn_match_phrases">語句の一致</string>
+ <string name="btn_share_encrypted_signed">暗号化/署名とテキストをシェア</string>
+ <string name="btn_copy_encrypted_signed">暗号化/署名とテキストをコピー</string>
<string name="btn_view_cert_key">検証した鍵を見る</string>
<string name="btn_create_key">鍵の生成</string>
<string name="btn_add_files">ファイルの追加</string>
- <string name="btn_share_decrypted_text">復号化したテキストの共有</string>
+ <string name="btn_share_decrypted_text">共有</string>
+ <string name="btn_open_with">...で開く</string>
<string name="btn_copy_decrypted_text">復号化したテキストのコピー</string>
<string name="btn_decrypt_clipboard">クリップボードから読み取り</string>
<string name="btn_decrypt_files">入力ファイルの選択</string>
@@ -87,10 +96,11 @@
<string name="btn_add_keyserver">追加</string>
<string name="btn_save_default">デフォルトとして保存</string>
<string name="btn_saved">保存しました!</string>
+ <string name="btn_not_matching">一致せず</string>
<!--menu-->
<string name="menu_preferences">設定</string>
<string name="menu_help">ヘルプ</string>
- <string name="menu_export_key">ファイルへバックアップ</string>
+ <string name="menu_export_key">バックアップ鍵</string>
<string name="menu_delete_key">鍵の削除</string>
<string name="menu_manage_keys">自分の鍵の管理</string>
<string name="menu_search">検索</string>
@@ -101,8 +111,9 @@
<string name="menu_export_all_keys">すべての鍵のエクスポート</string>
<string name="menu_update_all_keys">全部のキーをアップデートする</string>
<string name="menu_advanced">拡張情報</string>
- <string name="menu_certify_fingerprint">指紋比較による確認</string>
- <string name="menu_export_log">エクスポートログ</string>
+ <string name="menu_certify_fingerprint">指紋による確認</string>
+ <string name="menu_certify_fingerprint_phrases">語句による検証</string>
+ <string name="menu_share_log">共有ログ</string>
<string name="menu_keyserver_add">追加</string>
<!--label-->
<string name="label_message">テキスト</string>
@@ -111,6 +122,7 @@
<string name="label_file_colon">ファイル:</string>
<string name="label_no_passphrase">パスワードなし</string>
<string name="label_passphrase">パスワード</string>
+ <string name="label_pin">PIN</string>
<string name="label_unlock">アンロック...</string>
<string name="label_passphrase_again">再度パスワードを入力</string>
<string name="label_show_passphrase">パスワード表示</string>
@@ -119,9 +131,7 @@
<string name="label_file_ascii_armor">アスキー形式ファイルを有効</string>
<string name="label_write_version_header">OpenKeychainの利用を通知する</string>
<string name="label_write_version_header_summary">OpenPGPの 署名、暗号文、そしてエクスポートした鍵に \'OpenKeychain v2.7\' と書くようになりました</string>
- <string name="label_use_default_yubikey_pin">デフォルトのYubikey PINを使用する</string>
<string name="label_use_num_keypad_for_yubikey_pin">Yubikey PINで数字キーパッドを使う</string>
- <string name="label_label_use_default_yubikey_pin_summary"> NFC越しにYubikeyにアクセスするためデフォルトのPIN (123456) を使用する</string>
<string name="label_asymmetric_from">署名:</string>
<string name="label_to">暗号化:</string>
<string name="label_delete_after_encryption">暗号化後にファイル削除</string>
@@ -145,7 +155,7 @@
<string name="label_name">名前</string>
<string name="label_comment">コメント</string>
<string name="label_email">Eメールアドレス</string>
- <string name="label_send_key">クラウドによる同期</string>
+ <string name="label_send_key">インターネットでの同期</string>
<string name="label_fingerprint">指紋</string>
<string name="expiry_date_dialog_title">期限日時を設定</string>
<string name="label_keyservers_title">鍵サーバ</string>
@@ -155,8 +165,9 @@
<string name="label_enable_compression">圧縮を有効</string>
<string name="label_encrypt_filenames">暗号化するファイル名</string>
<string name="label_hidden_recipients">受信者を隠す</string>
- <string name="label_verify_keyserver">鍵サーバを検証</string>
- <string name="label_enter_keyserver_url">鍵サーバのURLを入力</string>
+ <string name="label_verify_keyserver_connection">テスト接続</string>
+ <string name="label_only_trusted_keyserver">安全な鍵サーバのみ</string>
+ <string name="label_enter_keyserver_url">URL</string>
<string name="label_keyserver_dialog_delete">鍵サーバの削除</string>
<string name="label_theme">テーマ</string>
<string name="pref_keyserver">OpenPGP鍵サーバ</string>
@@ -166,11 +177,20 @@
<string name="label_sync_settings_keyserver_title">鍵の自動アップデート</string>
<string name="label_sync_settings_keyserver_summary_on">1週間以上古い鍵なら鍵サーバへアップデートを問合せる</string>
<string name="label_sync_settings_keyserver_summary_off">鍵を自動でアップデートしない</string>
- <string name="label_sync_settings_contacts_title">鍵の連絡先を同期する</string>
- <string name="label_sync_settings_contacts_summary_on">オフランで完結した、鍵と連絡先のメールアドレスでの関連付けを行う</string>
+ <string name="label_sync_settings_contacts_title">連絡先へ鍵をリンク</string>
+ <string name="label_sync_settings_contacts_summary_on">オフランで完結して、名前とメールアドレスに基づいて、鍵を連絡先にリンク</string>
<string name="label_sync_settings_contacts_summary_off">新しい鍵は連絡先と関連付けしない</string>
<!--label shown in Android settings under the OpenKeychain account-->
<string name="keyserver_sync_settings_title">鍵の自動アップデート</string>
+ <string name="label_experimental_settings_desc_title">注意</string>
+ <string name="label_experimental_settings_desc_summary">これらの機能はまだ完成していないか、ユーザーエクスペリエンス/セキュリティ研究の結果ではありません。そのため、このセキュリティに依存したり、遭遇した問題を報告しないでください!</string>
+ <string name="label_experimental_settings_word_confirm_title">語句検証</string>
+ <string name="label_experimental_settings_word_confirm_summary">16進指紋の変りに語句で鍵を検証</string>
+ <string name="label_experimental_settings_linked_identities_title">リンクしたユーザID</string>
+ <string name="label_experimental_settings_linked_identities_summary">Twitter、GitHub、Webサイト、またはDNSに鍵をリンク (keybase.ioに似ていますが、分散型)</string>
+ <string name="label_experimental_settings_keybase_title">Keybase.io 検証</string>
+ <string name="label_experimental_settings_keybase_summary">鍵の検証のためkeybase.ioに連絡し、鍵が表示されるたびに表示します</string>
+ <string name="label_experimental_settings_theme_summary">(アイコンおよび多くの画面は、まだダークテーマに応じて調整されていません)</string>
<!--Proxy Preferences-->
<string name="pref_proxy_tor_title">Torを有効</string>
<string name="pref_proxy_tor_summary">Orbotのインストールが要求されます</string>
@@ -188,17 +208,18 @@
<!--InstallDialogFragment strings-->
<string name="orbot_install_dialog_title">Torで使うOrbotをインストールしますか?</string>
<string name="orbot_install_dialog_install">インストール</string>
+ <string name="orbot_install_dialog_content">Orbotをインストールして、それを介したプロキシトラフィックを有効にする必要があります。インストールしますか?</string>
<string name="orbot_install_dialog_cancel">キャンセル</string>
- <string name="orbot_install_dialog_ignore_tor">Torを使わない</string>
+ <string name="orbot_install_dialog_ignore_tor">Torを使わないあ</string>
<!--StartOrbotDialogFragment strings-->
<string name="orbot_start_dialog_title">Orbotを始めますか?</string>
- <string name="orbot_start_dialog_content">Orbot は動作しても表れません。スタートしてTorに接続しますか?</string>
+ <string name="orbot_start_dialog_content">Orbot は動作していないようです。起動して Tor に接続しますか?</string>
<string name="orbot_start_btn">Orbotを始める</string>
<string name="orbot_start_dialog_start">Orbotを始める</string>
<string name="orbot_start_dialog_cancel">キャンセル</string>
<string name="orbot_start_dialog_ignore_tor">Torを使わない</string>
- <string name="user_id_no_name">&lt;名前なし&gt;</string>
- <string name="none">&lt;無し&gt;</string>
+ <string name="user_id_no_name"><![CDATA[<no name>]]></string>
+ <string name="none"><![CDATA[<none>]]></string>
<plurals name="n_keys">
<item quantity="other">%d個の鍵</item>
</plurals>
@@ -220,6 +241,7 @@
<string name="choice_4hours">4時間</string>
<string name="choice_8hours">8時間</string>
<string name="choice_forever">永遠</string>
+ <string name="choice_select_cert">鍵を選択</string>
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
@@ -240,7 +262,8 @@
<string name="no_filemanager_installed">互換性のないファイルマネージャがインストールされています。</string>
<string name="passphrases_do_not_match">パスワードが一致しません。</string>
<string name="passphrase_must_not_be_empty">パスワードを入れてください。</string>
- <string name="passphrase_for_symmetric_encryption">対称暗号。</string>
+ <string name="passphrase_for_symmetric_encryption">パスワードの入力</string>
+ <string name="passphrase_for_backup">バックアップコードの入力</string>
<string name="passphrase_for">\'%s\' にパスワードを入れてください</string>
<string name="pin_for">\'%s\' にPINを入力してください</string>
<string name="yubikey_pin_for">\'%s\' の Yubikey にアクセスするためのPINを入力してください</string>
@@ -258,8 +281,12 @@
<string name="error_no_encryption_or_signature_key">少なくとも1つの暗号化鍵か署名鍵を選択して下さい。</string>
<string name="specify_file_to_encrypt_to">どれのファイルを暗号化するのを入力してください。\n注意:ファイルが存在しているなら上書きされる!</string>
<string name="specify_file_to_decrypt_to">どれのファイルを暗号するのを入力してください。\n注意:ファイルが存在しているなら上書きされる!</string>
+ <string name="specify_backup_dest">鍵を除いてバックアップが行われます。保存先のファイルを指定してください。\n警告: ファイルが存在する場合、上書きされます!</string>
+ <string name="specify_backup_dest_single">この鍵は共有されます。保存先のファイルを指定してください。\n警告: ファイルが存在する場合、上書きされます!</string>
+ <string name="specify_backup_dest_secret_single">鍵のフルバックアップが行われます。保存先のファイルを指定してください。\n警告: ファイルが存在する場合、上書きされます!</string>
+ <string name="specify_backup_dest_secret">あなたの鍵を含めて、すべての鍵のフルバックアップが行われます。保存先のファイルを指定してください。\n警告: ファイルが存在する場合、上書きされます!</string>
<string name="key_deletion_confirmation_multi">選択したすべての鍵を本当に削除してよいですか?</string>
- <string name="secret_key_deletion_confirmation">削除後はこの鍵で暗号化されたメッセージが読めなくなります、またその鍵で行われたすべての鍵確認を失います!</string>
+ <string name="secret_key_deletion_confirmation">削除後はこの鍵で暗号化されたメッセージ/ファイルが読めなくなります、またその鍵で行われたすべての鍵確認を失います!</string>
<string name="public_key_deletetion_confirmation">鍵 \'%s\' を削除しますか?</string>
<string name="also_export_secret_keys">秘密鍵もエクスポートします</string>
<string name="reinstall_openkeychain">あなたは既知のAndroidのバグに遭遇しました。もし鍵とあなたの連絡先をリンクさせたいならOpenKeychainを再インストールしてください。</string>
@@ -268,8 +295,6 @@
<string name="no_keys_exported">鍵をエクスポートしていません。</string>
<string name="key_creation_el_gamal_info">ノート: 副鍵はElGamalでのみサポートされます。</string>
<string name="key_not_found">鍵 %08X は見付かりませんでした。</string>
- <string name="specify_file_to_export_log_to">ファイルをどこにエクスポートするか決めてください。
-注意: 既存のファイルがあると上書きされます。</string>
<plurals name="bad_keys_encountered">
<item quantity="other">%d の問題ある鍵を無視しました。 おそらく次のオプションでエクスポートしています
--export-secret-subkeys
@@ -282,7 +307,6 @@
<string name="key_copied_to_clipboard">鍵はクリップボードにコピーされました!</string>
<string name="fingerprint_copied_to_clipboard">指紋はクリップボードにコピーされました!</string>
<string name="select_key_to_certify">確認に使う鍵を選択して下さい!</string>
- <string name="key_too_big_for_sharing">この共有方法では鍵が大きすぎます!</string>
<string name="text_copied_to_clipboard">鍵はクリップボードにコピーされました!</string>
<!--errors
no punctuation, all lowercase,
@@ -369,8 +393,8 @@
<string name="progress_encrypting">データの暗号化中...</string>
<string name="progress_decrypting">データの復号化中...</string>
<string name="progress_preparing_signature">署名の準備中...</string>
- <string name="progress_generating_signature">署名の生成中...</string>
<string name="progress_processing_signature">署名処理中...</string>
+ <string name="progress_generating_signature">署名の生成中...</string>
<string name="progress_verifying_signature">署名の検証中...</string>
<string name="progress_signing">署名中...</string>
<string name="progress_certifying">検証中...</string>
@@ -382,15 +406,11 @@
<string name="progress_deleting">鍵の削除中...</string>
<string name="progress_con_saving">統合: キャッシュへ保存…</string>
<string name="progress_con_reimport">統合: 再インポート中…</string>
- <string name="progress_verifying_keyserver_url">鍵サーバの検証...</string>
+ <string name="progress_verifying_keyserver_connection">接続の検証中...</string>
<string name="progress_starting_orbot">Orbotを始める...</string>
<!--action strings-->
<string name="hint_cloud_search_hint">名前、Email...で検索</string>
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -420,7 +440,7 @@
<string name="help_about_version">バージョン:</string>
<!--Import-->
<string name="import_tab_keyserver">鍵サーバ</string>
- <string name="import_tab_cloud">検索をクラウドで</string>
+ <string name="import_tab_cloud">鍵の検索</string>
<string name="import_tab_direct">ファイル/クリップボード</string>
<string name="import_tab_qr_code">QRコード/NFC</string>
<string name="import_import">選択した鍵のインポート</string>
@@ -437,10 +457,10 @@
<string name="with_cancelled">、キャンセルされるまで</string>
<!--Import result toast-->
<plurals name="import_keys_added_and_updated_1">
- <item quantity="other">%1$d の鍵のインポートに成功</item>
+ <item quantity="other">%1$d の鍵のインポートに成功。</item>
</plurals>
<plurals name="import_keys_added_and_updated_2">
- <item quantity="other">そして、%1$d の鍵を %2$s アップデートした。</item>
+ <item quantity="other">そして %1$d の鍵%2$s をアップロードしました。</item>
</plurals>
<plurals name="import_keys_added">
<item quantity="other">%1$d の鍵%2$sのインポートに成功。</item>
@@ -478,7 +498,7 @@
<string name="revoke_cancelled">破棄操作をキャンセルしました。</string>
<!--Certify result toast-->
<plurals name="certify_keys_ok">
- <item quantity="other">%1$d 個の鍵 %2$s の検証に成功。</item>
+ <item quantity="other">%1$d の鍵%2$sの検証に成功。</item>
</plurals>
<plurals name="certify_keys_with_errors">
<item quantity="other">%d 個の鍵で検証失敗!</item>
@@ -536,9 +556,12 @@
<string name="share_nfc_dialog">NFCで共有</string>
<!--retry upload dialog-->
<string name="retry_up_dialog_title">アップロード失敗</string>
+ <string name="retry_up_dialog_message">アップロードに失敗しました。操作を再実行しますか?</string>
<string name="retry_up_dialog_btn_reupload">操作再実行</string>
<string name="retry_up_dialog_btn_cancel">操作取り止め</string>
<!--Delete or revoke private key dialog-->
+ <string name="del_rev_dialog_message">もうこの鍵を使用しない場合は、失効させて、アップロードすべきです。 OpenKeychainから鍵を削除して、どこか別の場所から使い続けたい場合は、\'削除のみ\' を選択してください。</string>
+ <string name="del_rev_dialog_title">鍵 \'%s\' を破棄/削除</string>
<string name="del_rev_dialog_btn_revoke">破棄とアップロード</string>
<string name="del_rev_dialog_btn_delete">削除のみ</string>
<!--Delete Or Revoke Dialog spinner-->
@@ -551,6 +574,9 @@
<string name="key_list_empty_text1">鍵が見当りません!</string>
<string name="key_list_filter_show_all">すべての鍵を表示</string>
<string name="key_list_filter_show_certified">検証済みの鍵のみ表示</string>
+ <string name="key_list_fab_qr_code">QCコードのスキャン</string>
+ <string name="key_list_fab_search">鍵の検索</string>
+ <string name="key_list_fab_import">ファイルからインポート</string>
<!--Key view-->
<string name="key_view_action_edit">鍵の編集</string>
<string name="key_view_action_encrypt">テキスト暗号化</string>
@@ -567,23 +593,16 @@
<string name="key_view_tab_keybase">Keybase.io</string>
<string name="user_id_info_revoked_title">破棄</string>
<string name="user_id_info_revoked_text">このIDは鍵の所有者により破棄されています。もう適正ではありません。</string>
- <string name="user_id_info_certified_title">検証済み</string>
- <string name="user_id_info_certified_text">このIDは貴方によって証明されています。</string>
+ <string name="user_id_info_certified_title">確認済み</string>
+ <string name="user_id_info_certified_text">このIDはあなたが確認済です。</string>
<string name="user_id_info_uncertified_title">未検証</string>
- <string name="user_id_info_uncertified_text">このIDはまだ検証されていません。IDが本当に特定の人に対応している場合を、あなたは確認することができません。</string>
+ <string name="user_id_info_uncertified_text">このIDはまだ確認されていません。IDが本当に特定の人に対応しているかを、あなたは確認することができません。</string>
<string name="user_id_info_invalid_title">無効</string>
<string name="user_id_info_invalid_text">このIDではなにかしら問題があります!</string>
<!--Key trust-->
- <string name="key_trust_already_verified">鍵はすでに確認されています!</string>
- <string name="key_trust_it_is_yours">これはあなたの鍵の内のひとつです!</string>
- <string name="key_trust_maybe">この鍵はすでに破棄されたか期限切れです。\n確認済みではなく、しかしあなたは信頼すると選択することもできます。</string>
- <string name="key_trust_revoked">このIDは鍵の所有者により破棄されています。信頼することはできません。</string>
- <string name="key_trust_expired">この鍵は期限切れです。信頼することができません。</string>
- <string name="key_trust_old_keys">このキーの有効な日付の時で書いてあるメッセージを復号化 するのは恐らく大丈夫です。</string>
- <string name="key_trust_no_cloud_evidence">この鍵の信頼性についてのクラウドでの検証がありません。</string>
+ <string name="key_trust_no_cloud_evidence">この鍵の信頼性についてのインターネットでの検証がありません。</string>
<string name="key_trust_start_cloud_search">検索開始</string>
<string name="key_trust_results_prefix">Keybase.ioはこのキーのオーナーだと言う証拠を提供している:</string>
- <string name="key_trust_header_text">注意:Keybase.ioのオーナー証拠は実験的な機会です。キーを確認することに加えて、QRコードや、NFCでキーを交換するのもお勧めする。</string>
<!--keybase proof stuff-->
<string name="keybase_narrative_twitter">Twitterへ以下のIDで投稿 %s</string>
<string name="keybase_narrative_github">Githubでは %s で知られています</string>
@@ -641,7 +660,7 @@
<string name="edit_key_error_bad_nfc_size">スマートカードでは鍵サイズをサポートしません!</string>
<string name="edit_key_error_bad_nfc_stripped">鍵をスマートカードに移動できません(ストリップしてあるか、\'カードへ迂回\'がない)</string>
<!--Create key-->
- <string name="create_key_upload">クラウドとの同期</string>
+ <string name="create_key_upload">インターネットでの同期</string>
<string name="create_key_empty">このフィールドは必須です</string>
<string name="create_key_passphrases_not_equal">パスワードが一致しない</string>
<string name="create_key_final_text">あたなが入力したIDは以下です:</string>
@@ -657,12 +676,14 @@
<string name="create_key_add_email_text">追加のEメールアドレスがこの鍵に紐付きそしてセキュアな通信に使うことができます。</string>
<string name="create_key_email_already_exists_text">メールアドレスがすでに追加されている</string>
<string name="create_key_email_invalid_email">メールアドレスのフォーマットが無効です</string>
+ <string name="create_key_yubi_key_pin_text">6桁の数字でPINを選んでください。</string>
+ <string name="create_key_yubi_key_admin_pin_text">管理者PINを書き留めて、安全な場所に保管してください (PINを3回間違ったときに必要になります)。</string>
<string name="create_key_yubi_key_pin">PIN</string>
<string name="create_key_yubi_key_admin_pin">管理者PIN</string>
- <string name="create_key_yubi_key_pin_repeat_text">処理を続けるためPINおよび管理者PINの入力をしてください。</string>
<string name="create_key_yubi_key_pin_repeat">再度PINを入力</string>
- <string name="create_key_yubi_key_admin_pin_repeat">再度管理者PINを入力</string>
<string name="create_key_yubi_key_pin_not_correct">PINが正しくありません!</string>
+ <string name="create_key_yubi_key_pin_too_short">PINは最低数字6字長は必要です!</string>
+ <string name="create_key_yubi_key_pin_insecure">000000、123456、のような似た組み合わせではない、安全なPINを選んでください。</string>
<!--View key-->
<string name="view_key_revoked">破棄: 鍵はもう使われません!</string>
<string name="view_key_expired">期限切れ: この連絡先は鍵の妥当性を拡張する必要があります!</string>
@@ -674,11 +695,13 @@
<!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">鍵サーバを追加</string>
<string name="edit_keyserver_dialog_title">鍵サーバの編集</string>
- <string name="add_keyserver_verified">鍵サーバを検証しました!</string>
+ <string name="add_keyserver_connection_verified">接続が検証されました!</string>
<string name="add_keyserver_without_verification">鍵サーバを検証なしで追加した。</string>
<string name="add_keyserver_invalid_url">無効なURLです!</string>
- <string name="add_keyserver_connection_failed">鍵サーバへの接続し失敗。URLとあなたのインターネット接続をチェックしてください。</string>
+ <string name="add_keyserver_keyserver_not_trusted">信頼された鍵サーバではありません (ピンニング証明書は利用できません)!</string>
+ <string name="add_keyserver_connection_failed">鍵サーバへの接続に失敗しました。URLとインターネット接続をチェックしてください。</string>
<string name="keyserver_preference_deleted">%s を削除</string>
+ <string name="keyserver_preference_cannot_delete_last">最後の鍵サーバは削除できません。少なくとも一つは必要です!</string>
<!--Navigation Drawer-->
<string name="nav_keys">鍵</string>
<string name="nav_encrypt_decrypt">暗号化/復号化</string>
@@ -686,7 +709,7 @@
<string name="drawer_open">ナビゲーションドロワーを開く</string>
<string name="drawer_close">ナビゲーションドロワーを閉める</string>
<string name="my_keys">自分の鍵</string>
- <string name="nav_backup">バックアップ</string>
+ <string name="nav_backup">バックアップ/リストア</string>
<!--hints-->
<string name="encrypt_content_edit_text_hint">テキストを入力</string>
<!--certs-->
@@ -712,6 +735,8 @@
<string name="msg_ip_error_op_exc">データベースエラーにより操作が失敗しました</string>
<string name="msg_ip_error_remote_ex">内部エラーにより操作が失敗しました</string>
<string name="msg_ip">公開鍵の鍵輪 %s をインポート</string>
+ <string name="msg_ip_fingerprint_error">インポートした鍵の鍵指紋が予期したものと一致しません!</string>
+ <string name="msg_ip_fingerprint_ok">指紋チェックOK</string>
<string name="msg_ip_insert_keyring">鍵輪データのエンコード中</string>
<string name="msg_ip_insert_keys">鍵の解析中</string>
<string name="msg_ip_prepare">データベース操作の準備</string>
@@ -799,7 +824,7 @@
<string name="msg_is_importing_subkeys">秘密鍵の副鍵の処理中</string>
<string name="msg_is_error_io_exc">鍵輪のエンコードエラー</string>
<string name="msg_is_merge_public">インポートしたデータ内に存在する公開鍵輪をマージ</string>
- <string name="msg_is_merge_secret">インポートしたデータ内に存在する秘密鍵輪をマージ</string>
+ <string name="msg_is_merge_secret">既存の秘密鍵輪にインポートしたデータをマージします</string>
<string name="msg_is_merge_special">公開鍵輪から自己署名データをマージ</string>
<string name="msg_is_pubring_generate">秘密鍵の鍵輪から公開鍵の鍵輪を生成中</string>
<string name="msg_is_subkey_nonexistent">秘密鍵の副鍵 %s が利用不可能</string>
@@ -867,6 +892,7 @@
<string name="msg_kc_uid_no_cert">ユーザID \'%s\' の正常な自己署名が見付かりませんでした、鍵輪から除去しました</string>
<string name="msg_kc_uid_remove">無効なユーザID \'%s\' を破棄中</string>
<string name="msg_kc_uid_dup">重複したユーザID \'%s\' を削除中。IDを二つもっています。この結果は署名を失っているためかもしれません!</string>
+ <string name="msg_kc_uid_too_many">ユーザーID \'%s\' を削除しています。100以上のユーザーIDがインポートされません!</string>
<string name="msg_kc_uid_warn_encoding">ユーザIDをUTF-8として検証できませんでした!</string>
<string name="msg_kc_uat_jpeg">JPEG型のユーザー属性の処理中</string>
<string name="msg_kc_uat_unknown">不明な型のユーザー属性の処理中</string>
@@ -898,7 +924,7 @@
<string name="msg_cr_error_no_user_id">鍵輪は最低でも1つのユーザIDの生成が必要です!</string>
<string name="msg_cr_error_no_certify">主鍵は検証フラグが必須です!</string>
<string name="msg_cr_error_null_expiry">鍵の生成時に期限を\'過去\'とすることはできません。これはプログラムエラーで、バグレポートでファイルを送ってください!</string>
- <string name="msg_cr_error_keysize_512">鍵サイズは512かそれ以上が必須です!</string>
+ <string name="msg_cr_error_keysize_2048">鍵サイズは2048かそれ以上が必須です!</string>
<string name="msg_cr_error_no_curve">鍵サイズが不明です! これはプログラムエラーで、バグレポートでファイルの提出をお願いします!</string>
<string name="msg_cr_error_no_keysize">楕円暗号が不明です! これはプログラムエラーで、バグレポートでファイルの提出をお願いします!</string>
<string name="msg_cr_error_internal_pgp">PGP内部エラー!</string>
@@ -910,6 +936,7 @@
<!--modifySecretKeyRing-->
<string name="msg_mr">鍵輪 %s を変更中</string>
<string name="msg_mf_divert">カードでの暗号化操作に切り替えられます</string>
+ <string name="msg_mf_error_divert_newsub">\'カードに迂回\' の主鍵に対する、新しい副鍵の作成はサポートされていません!</string>
<string name="msg_mf_error_divert_serial">カードに対比した鍵のシリアル番号には16バイトは必要です!これはプロラグラムエラーで、バグレポートでファイルの提出をお願いします!</string>
<string name="msg_mf_error_encode">エンコード例外!</string>
<string name="msg_mf_error_fingerprint">現実の鍵指紋が想定の1つと合致しませんでした!</string>
@@ -997,6 +1024,7 @@
<string name="msg_ed_caching_new">新しいパスワードをキャッシュ</string>
<string name="msg_ed_error_no_parcel">SaveKeyringParcel欠落!(これはバグです、レポートしてください)</string>
<string name="msg_ed_error_key_not_found">鍵が見当りません!</string>
+ <string name="msg_ed_error_extract_public_upload">公開鍵を抽出してのアップロードのエラー!</string>
<string name="msg_ed_fetching">フェッチした鍵を変更 (%s)</string>
<string name="msg_ed_success">鍵の操作に成功</string>
<!--Promote key-->
@@ -1015,6 +1043,7 @@
<string name="msg_dc_askip_not_allowed">受け入れた鍵で暗号化されていないデータです、スキップします...</string>
<string name="msg_dc_asym">鍵 %s で非対称の暗号化されたデータのブロックを検出</string>
<string name="msg_dc_charset">文字セットヘッダを発見: \'%s\'</string>
+ <string name="msg_dc_backup_version">バックアップバージョンヘッダを発見: \'%s\'</string>
<string name="msg_dc_clear_data">固定データを処理中</string>
<string name="msg_dc_clear_decompress">圧縮データの展開中</string>
<string name="msg_dc_clear_meta_file">ファイル名: %s</string>
@@ -1028,13 +1057,16 @@
<string name="msg_dc_clear_signature">後程署名データを保存します</string>
<string name="msg_dc_clear">平文データの処理中</string>
<string name="msg_dc_error_bad_passphrase">鍵のロック解除エラー、パスワードに問題があります!</string>
+ <string name="msg_dc_error_sym_passphrase">データの復号化エラー! (パスフレーズの間違い?)</string>
<string name="msg_dc_error_corrupt_data">データが破損しています!</string>
<string name="msg_dc_error_extract_key">鍵のロック解除で不明なエラー!</string>
<string name="msg_dc_error_integrity_check">完全性チェックエラー!</string>
<string name="msg_dc_error_invalid_data">正常ではないOpenPGPの暗号化か署名のデーータを検出しました!</string>
+ <string name="msg_dc_error_io">入力データの読み込みエラーが発生しました!</string>
<string name="msg_dc_error_input">入力データストリームのオープンエラー!</string>
<string name="msg_dc_error_no_data">ストリーム中に暗号化されたデータが見付からなかった!</string>
<string name="msg_dc_error_no_key">ストリーム中に既知の秘密鍵で暗号化されたデータが見付からなかった!</string>
+ <string name="msg_dc_error_no_signature">署名データを見失いました!</string>
<string name="msg_dc_error_pgp_exception">操作中にPGP例外に当たりました!</string>
<string name="msg_dc_integrity_check_ok">完全性チェックOK!</string>
<string name="msg_dc_ok_meta_only">メタデータだけが要求され、暗号化をスキップしました</string>
@@ -1050,10 +1082,16 @@
<string name="msg_dc_trail_sym">追跡で遭遇、対称暗号化されたデータ</string>
<string name="msg_dc_trail_unknown">追跡で未知のタイプのデータに遭遇</string>
<string name="msg_dc_unlocking">秘密鍵のロック解除</string>
+ <string name="msg_dc_insecure_encryption_key">安全でない暗号化鍵が使用されました! 鍵が古くなっているか、攻撃のために発生することがあります。</string>
+ <string name="msg_dc_insecure_symmetric_encryption_algo">安全でない暗号化アルゴリズムが使用されています! アプリケーションが古くなっているか、攻撃のために発生することがあります。</string>
+ <string name="msg_dc_insecure_hash_algo">安全でないハッシュアルゴリズムが使用されています! アプリケーションが古くなっているか、攻撃のために発生することがあります。</string>
+ <string name="msg_dc_insecure_mdc_missing">修正検出コード (MDC) パケットが欠落しています! 暗号化アプリケーションは古くなっているか、暗号強度低下攻撃がある場合に発生することがあります。</string>
+ <string name="msg_dc_insecure_key">安全でない鍵: RSA/DSA/エルガマルのビット長が短すぎるか、ECC曲線/アルゴリズムが安全でないと考えられます! アプリケーションが古くなっているか、攻撃のために発生することがあります。</string>
<!--Messages for VerifySignedLiteralData operation-->
<string name="msg_vl">署名の確認開始</string>
- <string name="msg_vl_error_no_siglist">署名済み固定データに署名リストがありません</string>
- <string name="msg_vl_error_wrong_key">メッセージが正しい鍵で署名されていません</string>
+ <string name="msg_vl_error_no_siglist">署名済み固定データに署名リストがありません!</string>
+ <string name="msg_vl_error_wrong_key">メッセージが正しい鍵で署名されていません!</string>
+ <string name="msg_vl_error_no_signature">署名データの検証中</string>
<string name="msg_vl_error_missing_literal">署名済み固定データにペイロードがありません</string>
<string name="msg_vl_clear_meta_file">ファイル名: %s</string>
<string name="msg_vl_clear_meta_mime">MIME種別: %s</string>
@@ -1073,7 +1111,6 @@
<string name="msg_se_success">署名/暗号化操作に成功!</string>
<!--Messages for PgpSignEncrypt operation-->
<string name="msg_pse_asymmetric">暗号化のための公開鍵の準備</string>
- <string name="msg_pse_clearsign_only">クリアテキスト署名の入力はサポートされていません!</string>
<string name="msg_pse_compressing">圧縮の準備</string>
<string name="msg_pse_encrypting">データ暗号化</string>
<string name="msg_pse_error_bad_passphrase">駄目なパスワード!</string>
@@ -1125,35 +1162,32 @@
</plurals>
<string name="msg_import_fetch_error_decode">鍵輪のデコードエラー</string>
<string name="msg_import_fetch_error">鍵の展開ができません! (ネットワークの問題?)</string>
+ <string name="msg_import_fetch_error_keyserver">鍵サーバから展開できません: %s</string>
+ <string name="msg_import_fetch_error_keyserver_secret">鍵サーバから秘密鍵をインポートできません!</string>
<string name="msg_import_fetch_keybase">keybase.ioから回収: %s</string>
- <string name="msg_import_fetch_error_keyserver">鍵サーバからの展開: %s</string>
<string name="msg_import_fetch_keyserver">鍵サーバからの回収: %s</string>
<string name="msg_import_fetch_keyserver_ok">鍵の展開に成功</string>
<string name="msg_import_keyserver">鍵サーバ %s を使う</string>
- <string name="msg_import_fingerprint_error">フェッチした鍵の鍵指紋が完全には一致しませんでした!</string>
- <string name="msg_import_fingerprint_ok">指紋チェックOK!</string>
<string name="msg_import_merge">展開したデータをマージ</string>
<string name="msg_import_merge_error">展開したデータのマージでエラー!</string>
<string name="msg_import_error">インポート操作に失敗!</string>
<string name="msg_import_error_io">I/Oエラーによりインポート操作が失敗しました!</string>
<string name="msg_import_partial">インポート操作に成功、ただしエラーあり!</string>
<string name="msg_import_success">インポート操作に成功!</string>
- <plurals name="msg_export">
- <item quantity="other">%d 個の鍵のエクスポート</item>
+ <plurals name="msg_backup">
+ <item quantity="other">%d の鍵とバックアップ</item>
</plurals>
- <string name="msg_export_all">すべての鍵のエクスポート</string>
- <string name="msg_export_public">公開鍵 %s のエクスポート</string>
- <string name="msg_export_secret">秘密鍵 %s のエクスポート</string>
- <string name="msg_export_error_no_file">指定のファイル名のファイルはありません!</string>
- <string name="msg_export_error_fopen">ファイルオープン中のエラー!</string>
- <string name="msg_export_error_no_uri">指定のURIはありません!</string>
- <string name="msg_export_error_uri_open">URIオープン中のエラー!</string>
- <string name="msg_export_error_storage">ストレージが書き込み準備できていません!</string>
- <string name="msg_export_error_db">データベースエラー!</string>
- <string name="msg_export_error_io">入出力エラー!</string>
- <string name="msg_export_error_key">鍵データの事前処理のエラー!</string>
- <string name="msg_export_success">エクスポート操作に成功!</string>
- <string name="msg_export_upload_success">鍵サーバへアップロードに成功</string>
+ <string name="msg_backup_all">すべての鍵とバックアップ</string>
+ <string name="msg_backup_public">公開鍵 %s のバックアップを作成中</string>
+ <string name="msg_upload">公開鍵 %s をアップロード中</string>
+ <string name="msg_backup_secret">秘密鍵 %s のバックアップを作成中</string>
+ <string name="msg_backup_error_uri_open">URIオープン時にエラー!</string>
+ <string name="msg_backup_error_db">データベースエラー!</string>
+ <string name="msg_backup_error_io">入出力エラー!</string>
+ <string name="msg_upload_error_key">鍵データの事前処理のエラー!</string>
+ <string name="msg_upload_error_upload">サーバに鍵をアップロード中にエラー! インターネット接続を確認してください</string>
+ <string name="msg_backup_success">バックアップ操作に成功</string>
+ <string name="msg_upload_success">鍵サーバへアップロードに成功</string>
<string name="msg_del_error_empty">削除するものがありません!</string>
<string name="msg_del_error_multi_secret">秘密鍵は個別にしか削除できません!</string>
<plurals name="msg_del">
@@ -1173,6 +1207,47 @@
<string name="msg_revoke_key">鍵 %s を破棄中</string>
<string name="msg_revoke_key_fail">鍵の破棄に失敗しました</string>
<string name="msg_revoke_ok">鍵の破棄に成功しました</string>
+ <!--Linked Identity verification-->
+ <string name="msg_lv">リンクしたユーザIDの検証中…</string>
+ <string name="msg_lv_match">トークンを検索</string>
+ <string name="msg_lv_match_error">リソースにトークンが見つかりません!</string>
+ <string name="msg_lv_fp_ok">指紋OK。</string>
+ <string name="msg_lv_fp_error">指紋不一致!</string>
+ <string name="msg_lv_error_twitter_auth">Twitter認証トークン取得エラー!</string>
+ <string name="msg_lv_error_twitter_handle">応答で、Twitterアカウントハンドルが不整合です!</string>
+ <string name="msg_lv_error_twitter_response">Twitter APIから予期しない応答!</string>
+ <string name="msg_lv_error_github_handle">応答で、GitHubアカウントハンドルが不整合です!</string>
+ <string name="msg_lv_error_github_not_found">Gistは、一致するファイルが含まれていません!</string>
+ <string name="msg_lv_fetch">URI \'%s\' 取得中</string>
+ <string name="msg_lv_fetch_redir">\'%s\' へのリダイレクト続行中</string>
+ <string name="msg_lv_fetch_ok">取得に成功しました (HTTP %s)</string>
+ <string name="msg_lv_fetch_error">サーバエラー (HTTP %s)</string>
+ <string name="msg_lv_fetch_error_url">URLが不正な形式です!</string>
+ <string name="msg_lv_fetch_error_io">IOエラー!</string>
+ <string name="msg_lv_fetch_error_format">フォーマットエラー!</string>
+ <string name="msg_lv_fetch_error_nothing">リソースが見つかりません!</string>
+ <string name="msg_data">入力データの処理中</string>
+ <string name="msg_data_openpgp">OpenPGPデータの処理を試みています</string>
+ <string name="msg_data_detached">分離署名に遭遇しました</string>
+ <string name="msg_data_detached_clear">以前の、未署名のデータをクリアしました!</string>
+ <string name="msg_data_detached_sig">分離署名の処理中</string>
+ <string name="msg_data_detached_raw">署名データの処理中</string>
+ <string name="msg_data_detached_nested">ネストされた署名データをスキップしています!</string>
+ <string name="msg_data_detached_trailing">署名された部分の後、末尾のデータをスキップしています!</string>
+ <string name="msg_data_detached_unsupported">サポートしない種別の分離署名!</string>
+ <string name="msg_data_error_io">入力データの読み込み時にエラー!</string>
+ <string name="msg_data_error_openpgp">OpenPGPデータの処理中にエラー!</string>
+ <string name="msg_data_mime_bad">MIMEデータとして解析できません</string>
+ <string name="msg_data_mime_filename">ファイル名: \'%s\'</string>
+ <string name="msg_data_mime_from_extension">拡張子からMIME種別を推測しています</string>
+ <string name="msg_data_mime_length">コンテンツ長: %s</string>
+ <string name="msg_data_mime">MIMEデータ構造の解析中</string>
+ <string name="msg_data_mime_ok">\"解析完了</string>
+ <string name="msg_data_mime_none">MIME構造が見つかりません</string>
+ <string name="msg_data_mime_part">MIME部分の処理中</string>
+ <string name="msg_data_mime_type">コンテンツ種別: %s</string>
+ <string name="msg_data_ok">データの処理に成功</string>
+ <string name="msg_data_skip_mime">MIME解析をスキップしています</string>
<string name="msg_acc_saved">アカウント保存</string>
<string name="msg_download_success">ダウンロードに成功しました!</string>
<string name="msg_download_no_valid_keys">ファイル/クリップボードにて正しい鍵が見付かりません!</string>
@@ -1185,18 +1260,17 @@
<string name="msg_download_query_too_short_or_too_many_responses">鍵がまったく無いか、多すぎる鍵が見付かりました。クエリを改善してください!</string>
<string name="msg_download_query_failed">鍵の検索時にエラーが発生しました。</string>
<!--Messages for Keybase Verification operation-->
+ <string name="msg_keybase_verification">%s のkeybase検証を試行中</string>
<string name="msg_keybase_error_no_prover">%s で検証チェッカを見付けることができませんでした</string>
<string name="msg_keybase_error_fetching_evidence">検証の取得で問題がある</string>
<string name="msg_keybase_error_key_mismatch">鍵の指紋が証明ポストと一致しませんでした</string>
<string name="msg_keybase_error_dns_fail">DNS TXT レコードの検索が失敗</string>
<string name="msg_keybase_error_specific">%s</string>
<string name="msg_keybase_error_msg_payload_mismatch">復号化した検証ポストが指定した値と一致しない</string>
- <!--Messages for Export Log operation-->
- <string name="msg_export_log_start">ログのエクスポート</string>
- <string name="msg_export_log_error_fopen">ファイルオープン中のエラー</string>
- <string name="msg_export_log_error_no_file">指定のファイル名のファイルはありません!</string>
- <string name="msg_export_log_error_writing">ファイルへの書き込みでI/Oエラー!</string>
- <string name="msg_export_log_success">ログのエクスポートに成功しました!</string>
+ <!--Messages for Mime parsing operation-->
+ <string name="msg_mime_parsing_start">MIME構造の解析中</string>
+ <string name="msg_mime_parsing_error">MIME解析に失敗</string>
+ <string name="msg_mime_parsing_success">MIME解析に成功!</string>
<!--PassphraseCache-->
<string name="passp_cache_notif_click_to_clear">タッチしてパスワードをクリア。</string>
<plurals name="passp_cache_notif_n_keys">
@@ -1206,27 +1280,34 @@
<string name="passp_cache_notif_clear">パスワードのクリア</string>
<string name="passp_cache_notif_pwd">パスワード</string>
<!--Keyserver sync-->
+ <string name="keyserver_sync_orbot_notif_title">サーバからの同期にはOrbotが必要です</string>
+ <string name="keyserver_sync_orbot_notif_msg">タップしてOrbotを開始</string>
+ <string name="keyserver_sync_orbot_notif_start">Orbotを始める</string>
+ <string name="keyserver_sync_orbot_notif_ignore">直接</string>
<!--First Time-->
<string name="first_time_text1">OpenKeychainであなたのプライバシーを取り戻しましょう!</string>
<string name="first_time_create_key">自分のキーを作る</string>
<string name="first_time_import_key">ファイルから鍵をインポート</string>
<string name="first_time_yubikey">YubiKey NEOを使用する</string>
<string name="first_time_skip">セットアップをスキップ</string>
+ <string name="first_time_blank_yubikey">OpenKeychainで、この空白のYubiKey NEOを使用しますか?\n\nYubiKeyを取り除いてください。再度必要になったときにプロンプトが表示されます!</string>
<string name="first_time_blank_yubikey_yes">YubiKeyを使用する</string>
+ <string name="backup_text">あなた自身の鍵を含んだバックアップは、決して他の人と共有しないでください!</string>
<string name="backup_all">すべての鍵とあなた所有の鍵</string>
<string name="backup_public_keys">すべての鍵</string>
<string name="backup_section">バックアップ</string>
+ <string name="restore_section">リストア</string>
<!--unsorted-->
<string name="section_certifier_id">検証者</string>
<string name="section_cert">証明の詳細</string>
<string name="label_user_id">ユーザID</string>
- <string name="unknown_uid">&lt;不明&gt;</string>
+ <string name="unknown_uid"><![CDATA[<unknown>]]></string>
<string name="empty_certs">この鍵に証明がない</string>
<string name="certs_text">あなたの検証された自己証明とあなたの鍵で生成された証明がここに表示されます</string>
<string name="section_uids_to_certify">ユーザID</string>
<string name="certify_text">インポートした鍵には\"アイデンティティ\": 名前とメールアドレス を含みます。正確に期待したものと一致しているか認定されているものを選択します。</string>
- <string name="certify_fingerprint_text">表示している指紋を、文字対文字で、あなたのパートナーの表示しているものと比較</string>
- <string name="certify_fingerprint_text2">表示している指紋は一致しましたか?</string>
+ <string name="certify_fingerprint_text">鍵指紋を、文字対文字で、相手の端末に表示しているものと比較</string>
+ <string name="certify_fingerprint_text_phrases">これらの語句を、相手の端末に表示しているものと比較</string>
<string name="label_revocation">破棄の理由</string>
<string name="label_cert_type">種別</string>
<string name="error_key_not_found">鍵が見当りません!</string>
@@ -1243,14 +1324,19 @@
<string name="contact_show_key">鍵 (%s) を表示</string>
<string name="swipe_to_update">下スワイプでキーサーバから更新します</string>
<string name="error_no_file_selected">暗号化するファイルを少なくとも1つ選択して下さい。</string>
+ <string name="error_multi_files">複数ファイルの保存はサポートされていません。これは現在のAndroidでの制限です。</string>
+ <string name="error_multi_clipboard">クリップボードへの複数ファイルの暗号化はサポートされていません。</string>
<string name="error_detached_signature">バイナリファイルの署名のみの操作はサポートされません、最低1つは暗号化鍵を選択してください。</string>
<string name="error_empty_text">テキストの入力を暗号化!</string>
+ <string name="error_log_share_internal">ログの準備中に内部エラー!</string>
<string name="key_colon">鍵:</string>
<string name="exchange_description">鍵交換の開始は、右側の参加者の番号を選択し、その後、\"交換開始\"ボタンを推します。\n\n2つ以上の質問で交換にいる右の参加者とその指紋が正しいかを確認してください。</string>
<string name="btn_start_exchange">交換開始</string>
<string name="user_id_none"><![CDATA[<none>]]></string>
<!--Android Account-->
+ <string name="account_no_manual_account_creation">手動でOpenKeychainのアカウントを作成することはできません。</string>
<string name="account_privacy_title">プライバシー</string>
+ <string name="account_privacy_text">OpenKeychainは、インターネットを使用して連絡先を同期しません。名前とメールアドレスに基づいて、鍵に連絡先をリンクするだけです。これはお使いのデバイス上でオフラインで行います。</string>
<!--Passphrase wizard-->
<!--TODO: rename all the things!-->
<string name="title_unlock_method">アンロックする手段を選択してください</string>
@@ -1282,21 +1368,36 @@
<string name="button_bind_key">鍵と紐付け</string>
<string name="yubikey_serno">シリアルナンバー: %s</string>
<string name="yubikey_key_holder">鍵ホルダ:</string>
- <string name="yubikey_key_holder_not_set">鍵ホルダ: &lt;未設定&gt;</string>
+ <string name="yubikey_key_holder_not_set"><![CDATA[Key holder: <not set>]]></string>
<string name="yubikey_status_bound">鍵がYubiKeyがマッチし紐付いている</string>
<string name="yubikey_status_unbound">YubiKeyがマッチ、鍵に紐付けることができる</string>
<string name="yubikey_status_partly">YubiKeyがマッチ、鍵に部分的に紐付いている</string>
<string name="yubikey_create">あなたのデバイスの背面にYubiKeyを固定してください。</string>
+ <string name="yubikey_reset_or_import">このYubiKeyは既に鍵を含んでいます。クラウドを使用して鍵をインポートしたり、YubiKeyをリセットすることができます。</string>
<string name="btn_import">インポート</string>
+ <string name="btn_reset">リセット</string>
+ <string name="yubikey_import_radio">鍵のインポート</string>
+ <string name="yubikey_reset_radio">YubiKeyをリセット</string>
+ <string name="yubikey_reset_warning">YubiKeyをリセットすると、その上のキーを完全に破壊します。その後は、この鍵で暗号化されたメッセージ/ファイルを復号化することができなくなります!</string>
<string name="snack_yubi_other">違う鍵がYubiKeyに格納されています!</string>
<string name="error_nfc">NFCエラー: %s</string>
+ <plurals name="error_pin">
+ <item quantity="other">PINが正しくありません! 再挑戦はあと%d回です。</item>
+ </plurals>
<string name="error_nfc_terminated">YubiKeyが完了状態</string>
+ <string name="error_nfc_wrong_length">入力されたPINが短すぎます。 PINの長さは少なくとも6桁にします。</string>
+ <string name="error_nfc_conditions_not_satisfied">使用条件を満たしていません。</string>
+ <string name="error_nfc_security_not_satisfied">セキュリティステータスを満していません。</string>
+ <string name="error_nfc_authentication_blocked">試行回数が多すぎるためPINがブロックされています。</string>
<string name="error_nfc_data_not_found">鍵もしくはオブジェクトが見当りません。</string>
<string name="error_nfc_unknown">不明なエラー</string>
<string name="error_nfc_bad_data">YubiKeyが不正なデータを報告した。</string>
+ <string name="error_nfc_chaining_error">YubiKeyがチェーン中の最後のコマンドを待っています。</string>
<string name="error_nfc_header">YubiKeyが不正な%sバイトを報告。</string>
+ <string name="error_nfc_tag_lost">YubiKeyを取り出すのが早すぎました。操作が完了するまでYubiKeyを戻してしてください。</string>
+ <string name="error_nfc_iso_dep_not_supported">タグは ISO-DEP (ISO 14443-4) をサポートしていません</string>
<string name="error_nfc_try_again">再実行</string>
- <string name="error_pin_nodefault">デフォルトのPINは棄却されました!</string>
+ <string name="error_pin_wrong">PINが正しくありません!</string>
<string name="error_temp_file">一時ファイルの生成でエラーしました。</string>
<string name="btn_delete_original">オリジナルのファイルを削除します</string>
<string name="snack_encrypt_filenames_on">ファイル名を暗号化<b>した</b>。</string>
@@ -1308,7 +1409,13 @@
<string name="error_loading_keys">鍵の読み込みエラー!</string>
<string name="error_empty_log">(エラー、空のログ)</string>
<string name="error_reading_text">復号化のための入力が読めない!</string>
+ <string name="error_reading_aosp">データの読み込みに失敗しました。これはAndroidメールクライアントのバグです! (Issue #290)</string>
+ <string name="error_reading_k9">不完全なデータを受信しました。 K-9 メールで、\'完全なメッセージをダウンロード\' を押してみてください!</string>
+ <string name="filename_unknown">不明なファイル名 (クリックして開きます)</string>
+ <string name="filename_unknown_text">テキスト(クリックして表示)</string>
+ <string name="filename_keys">鍵のバックアップ (クリックしてインポート)</string>
<string name="intent_show">署名/暗号化した内容を表示</string>
+ <string name="intent_share">署名/暗号化した内容を共有</string>
<string name="view_internal">OpenKeychainで閲覧</string>
<string name="error_preparing_data">データの処理でエラー!</string>
<string name="label_clip_title">暗号化データ</string>
@@ -1316,9 +1423,101 @@
<string name="error_saving_file">ファイルの保存でエラー!</string>
<string name="file_saved">ファイルを保存した!</string>
<string name="file_delete_ok">元のファイルを削除。</string>
+ <string name="file_delete_none">ファイルは削除されませんでした! (すでに削除済?)</string>
+ <string name="file_delete_exception">元のファイルは削除できませんでした!</string>
<string name="error_clipboard_empty">クリップボードが空です!</string>
<string name="error_clipboard_copy">クリップボードへのデータコピーでエラー!</string>
<string name="error_scan_fp">指紋の読み取りエラー!</string>
<string name="error_scan_match">指紋が一致しません!</string>
<string name="error_expiry_past">期限切れ日が過去です!</string>
+ <string name="linked_create_https_1_1">この種別のリンクしたユーザIDを作成することにより、あなたの鍵を制御するWebサイトにリンクすることができます。</string>
+ <string name="linked_create_https_1_2">これを行うには、このウェブサイトにテキストファイルを公開します。その後、それにリンクするIDを作成します。</string>
+ <string name="linked_create_https_1_3">検証のためにテキストファイルを配置することができるURLを入力してください。サーバがHTTPSをサポートして、有効なTLS証明書が必要であることに注意してください!</string>
+ <string name="linked_create_https_1_4">例: https://example.com/pgpkey.txt</string>
+ <string name="linked_create_https_created">検証ファイルが作成されました。次のステップでは、それを保存して、あなたが示されたURIにアップロードする必要があります:</string>
+ <string name="linked_create_https_2_1">このURIの検証ファイルが作成されました:</string>
+ <string name="linked_create_https_2_2">次のステップでは、このファイルを保存して、アップロードしてください。</string>
+ <string name="linked_create_https_2_3">ファイルが正しいURIで到達可能であることを確認してください。その後、セットアップを確認します。</string>
+ <string name="linked_create_https_2_4">検証に成功した後、終了ボタンを押して、鍵輪にリンクされたIDを追加し、処理を終了してください。</string>
+ <string name="linked_create_twitter_1_1">この種別のリンクしたユーザIDを作成することにより、あなたの鍵を制御するTwitterアカウントにリンクすることができます。</string>
+ <string name="linked_create_twitter_1_2">これを行うには、あなたのタイムラインで特定のツイートを公開し、その後、このツイートへのリンクされたIDを作成します。</string>
+ <string name="linked_create_twitter_1_3">続行するにはTwitterのスクリーンネームを入力してください。</string>
+ <string name="linked_create_twitter_handle">Twitter ハンドル</string>
+ <string name="linked_create_twitter_2_1">ボタンをクリックして、メッセージをツイートしてください!</string>
+ <string name="linked_create_twitter_2_2">括弧内のテキストが変更されていない限り、投稿する前にツイートを編集することができます。</string>
+ <string name="linked_create_twitter_2_3">&lt;b&gt;@%s&lt;/b&gt; としてあなたのツイートが公開されたら、検証ボタンをクリックして、あなたのタイムラインをスキャンしてください。</string>
+ <string name="linked_create_twitter_2_4">検証に成功した後、終了ボタンを押して、鍵輪にリンクされたIDを追加し、処理を終了してください。</string>
+ <string name="linked_create_verify">検証</string>
+ <string name="linked_text_clipboard">テキストをクリップボードにコピーしました</string>
+ <string name="linked_verified_https">このウェブサイトと鍵の間のリンクは確実に検証しました。<b>あなたがウェブサイトが本物であると思われる場合</b>、あなたの鍵でこの検証を確認します。</string>
+ <string name="linked_verified_github">このGitHubアカウントと鍵の間のリンクは確実に検証しました。<b>あなたがアカウントが本物であると思われる場合</b>、あなたの鍵でこの検証を確認します。</string>
+ <string name="linked_verified_dns">このドメイン名と鍵の間のリンクは確実に検証しました。<b>あなたがドメインが本物であると思われる場合</b>、あなたの鍵でこの検証を確認します。</string>
+ <string name="linked_verified_twitter">このTwitterアカウントと鍵の間のリンクは確実に検証しました。<b>あなたがアカウントが本物であると思われる場合</b>、あなたの鍵でこの検証を確認します。</string>
+ <string name="linked_verified_secret_https">すべて順番に検索します。</string>
+ <string name="linked_verified_secret_github">すべて順番に検索します。</string>
+ <string name="linked_verified_secret_dns">すべて順番に検索します。</string>
+ <string name="linked_verified_secret_twitter">すべて順番に検索します。</string>
+ <plurals name="linked_id_expand">
+ <item quantity="other">%d 以上の不明なユーザID種別があります</item>
+ </plurals>
+ <!--Other Linked Identity strings-->
+ <string name="linked_select_1">\'リンクしたユーザID\' は、あなたのPGP鍵をWeb上のリソースに接続します。</string>
+ <string name="linked_select_2">種別を選択してください: </string>
+ <string name="linked_id_generic_text">このファイルは、長いID %2$s のOpenPGP鍵の所有権を請求しています。\n\n検証のトークン:\n%1$s</string>
+ <string name="linked_id_github_text">このGistは私のOpenPGP鍵でリンクされたIDを確認し、このGitHubアカウントにリンクします。\n\n検証のトークン:\n%1$s</string>
+ <string name="linked_verifying">検証中…</string>
+ <string name="linked_verify_success">検証しました!</string>
+ <string name="linked_verify_error">検証エラー!</string>
+ <string name="linked_verify_pending">未検証</string>
+ <string name="linked_need_verify">次に進む前に、リソースを検証する必要があります!</string>
+ <string name="menu_linked_add_identity">アカウントへリンク</string>
+ <string name="section_linked_identities">リンクしたユーザID</string>
+ <string name="btn_finish">終了</string>
+ <string name="linked_title_https">Webサイト (HTTPS)</string>
+ <string name="linked_title_dns">ドメイン名 (DNS)</string>
+ <string name="linked_title_github">GitHub</string>
+ <string name="linked_title_twitter">Twitter</string>
+ <string name="card_linked_identity">リンクしたユーザID</string>
+ <string name="linked_button_verify">検証</string>
+ <string name="linked_button_retry">リトライ</string>
+ <string name="linked_button_retry_step">最後のステップを再試行</string>
+ <string name="linked_button_confirm">確認</string>
+ <string name="linked_button_view">閲覧</string>
+ <string name="linked_text_verifying">検証中…</string>
+ <string name="linked_text_error">エラー</string>
+ <string name="linked_text_confirming">確認中…</string>
+ <string name="linked_ids_more_unknown">%d 以上の不明なユーザID種別</string>
+ <string name="title_linked_id_create">リンクしたユーザIDを作成</string>
+ <string name="linked_github_text">この操作は、鍵をあなたのGitHubアカウントにリンクします。\nボタンを押すと続行します。</string>
+ <string name="linked_progress_auth_github">GitHubで認証…</string>
+ <string name="linked_progress_post_gist">Gistを投稿…</string>
+ <string name="linked_progress_update_key">鍵のアップデート…</string>
+ <string name="linked_button_start">Githubアカウントへリンク</string>
+ <string name="linked_error_auth_failed">認証に失敗!</string>
+ <string name="linked_error_timeout">接続タイムアウト!</string>
+ <string name="linked_error_network">ネットワークエラー!</string>
+ <string name="linked_error_http">通信エラー: %s</string>
+ <string name="linked_webview_title_github">GitHub認証</string>
+ <string name="linked_gist_description">OpenKeychain API テスト</string>
+ <string name="snack_btn_overwrite">上書</string>
+ <string name="backup_code_explanation">バックアップは、バックアップコードで保護されます。先に進む前に、それを書き留めてください!</string>
+ <string name="backup_code_enter">バックアップコードを入力してください:</string>
+ <string name="backup_code_ok">コードを受け付けました!</string>
+ <string name="btn_code_wrotedown">はい、書き留めました!</string>
+ <string name="backup_code_wrong">入力したバックアップコードが正しくありません!\n正しく書き留めましたか?</string>
+ <string name="btn_backup_share">バックアップを共有</string>
+ <string name="btn_backup_save">バックアップを保存</string>
+ <string name="snack_backup_error_saving">バックアップの保存中にエラー!</string>
+ <string name="snack_backup_saved">バックアップを保存しました</string>
+ <string name="snack_backup_exists">バックアップは既に存在します!</string>
+ <string name="snack_backup_saved_dir">OpenKeychainディレクトリに保存しました</string>
+ <string name="btn_backup_back">チェックに戻る</string>
+ <string name="snack_text_too_long">テキストが長すぎてすべて表示できません!</string>
+ <string name="snack_shared_text_too_long">長すぎたため、共有テキストをカットしました!</string>
+ <string name="share_log_dialog_title">ログを共有しますか?</string>
+ <string name="share_log_dialog_message">開発者がOpenKeychainのバグを見つけるためにログは非常に参考になりますが、更新された鍵に関するデータなど、潜在的な機密情報が含まれることがあります。この情報を共有しても大丈夫であることを確認してください。</string>
+ <string name="share_log_dialog_share_button">共有</string>
+ <string name="share_log_dialog_cancel_button">キャンセル</string>
+ <string name="toast_wrong_mimetype">データ種別が正しくありません。テキストを期待しました!</string>
+ <string name="toast_no_text">共有データにテキストはありません!</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-nl/strings.xml b/OpenKeychain/src/main/res/values-nl/strings.xml
index 1a02fdc07..cf870718e 100644
--- a/OpenKeychain/src/main/res/values-nl/strings.xml
+++ b/OpenKeychain/src/main/res/values-nl/strings.xml
@@ -29,7 +29,6 @@
<string name="title_exchange_keys">Sleutels uitwisselen</string>
<string name="title_advanced_key_info">Uitgebreide informatie</string>
<string name="title_delete_secret_key">JOUW sleutel \'%s\' verwijderen?</string>
- <string name="title_export_log">Log exporteren</string>
<string name="title_manage_my_keys">Beheer mijn sleutels</string>
<!--section-->
<string name="section_user_ids">Identiteiten</string>
@@ -37,11 +36,7 @@
<string name="section_linked_system_contact">Verbonden systeemcontact</string>
<string name="section_should_you_trust">Zou je deze sleutel vertrouwen?</string>
<string name="section_proof_details">Bewijs van verificatie</string>
- <string name="section_cloud_evidence">Bewijzen van de cloud</string>
<string name="section_keys">Subsleutels</string>
- <string name="section_cloud_search">Cloud zoeken</string>
- <string name="section_passphrase_cache">Verwerken van wachtwoorden/PINs</string>
- <string name="section_proxy_settings">Proxy-instellingen</string>
<string name="section_gui">Interface</string>
<string name="section_certify">Bevestigen</string>
<string name="section_actions">Acties</string>
@@ -68,12 +63,9 @@
<string name="btn_back">Terug</string>
<string name="btn_no">Nee</string>
<string name="btn_match">Vingerafdrukken komen overeen</string>
- <string name="btn_share_encrypted_signed">Tekst versleutelen en opslaan</string>
- <string name="btn_copy_encrypted_signed">Tekst versleutelen en kopiëren</string>
<string name="btn_view_cert_key">Toon certificatiesleutel</string>
<string name="btn_create_key">Sleutel aanmaken</string>
<string name="btn_add_files">Bestand(en) toevoegen</string>
- <string name="btn_share_decrypted_text">Ontsleutelde tekst delen</string>
<string name="btn_copy_decrypted_text">Ontsleutelde tekst kopiëren</string>
<string name="btn_decrypt_clipboard">Lezen van klembord</string>
<string name="btn_decrypt_files">Kies invoerbestand</string>
@@ -97,8 +89,6 @@
<string name="menu_export_all_keys">Alle sleutels exporteren</string>
<string name="menu_update_all_keys">Alle sleutels bijwerken</string>
<string name="menu_advanced">Uitgebreide informatie</string>
- <string name="menu_certify_fingerprint">Bevestigen door vingerafdrukken te vergelijken</string>
- <string name="menu_export_log">Log exporteren</string>
<string name="menu_keyserver_add">Toevoegen</string>
<!--label-->
<string name="label_message">Tekst</string>
@@ -115,9 +105,7 @@
<string name="label_file_ascii_armor">ASCII Armor aanzetten</string>
<string name="label_write_version_header">Laat anderen weten dat je OpenKeychain gebruikt</string>
<string name="label_write_version_header_summary">Voegt \'OpenKeychain v2.7\' toe aan OpenPGP ondertekeningen, cijfertekst en geëxporteerde sleutels</string>
- <string name="label_use_default_yubikey_pin">Gebruik standaard YubiKey PIN</string>
<string name="label_use_num_keypad_for_yubikey_pin">Gebruik numeriek toetsenbord voor YubiKey PIN</string>
- <string name="label_label_use_default_yubikey_pin_summary">Gebruikt standaard PIN (123456) om YubiKeys over NFC te bereiken</string>
<string name="label_asymmetric_from">Ondertekenen met:</string>
<string name="label_to">Versleutelen naar:</string>
<string name="label_delete_after_encryption">Verwijder bestanden na versleuteling</string>
@@ -141,7 +129,6 @@
<string name="label_name">Naam</string>
<string name="label_comment">Opmerking</string>
<string name="label_email">E-mailadres</string>
- <string name="label_send_key">Synchroniseren met de cloud</string>
<string name="label_fingerprint">Vingerafdruk</string>
<string name="expiry_date_dialog_title">Bepaal verloopdatum</string>
<string name="label_keyservers_title">Sleutelservers</string>
@@ -151,8 +138,6 @@
<string name="label_enable_compression">Compressie aanzetten</string>
<string name="label_encrypt_filenames">Versleutel bestandsnamen</string>
<string name="label_hidden_recipients">Verberg ontvangers</string>
- <string name="label_verify_keyserver">Sleutelserver verifiëren</string>
- <string name="label_enter_keyserver_url">Voer sleutelserver-URL in</string>
<string name="label_keyserver_dialog_delete">Sleutelserver verwijderen</string>
<string name="label_theme">Thema</string>
<string name="pref_keyserver">OpenPGP-sleutelservers</string>
@@ -173,22 +158,16 @@
<string name="pref_proxy_type_choice_http">HTTP</string>
<string name="pref_proxy_type_choice_socks">SOCKS</string>
<!--OrbotHelper strings-->
- <string name="orbot_ignore_tor">Gebruik Tor niet</string>
<!--InstallDialogFragment strings-->
<string name="orbot_install_dialog_title">Orbot installeren om Tor te gebruiken?</string>
<string name="orbot_install_dialog_install">Installeren</string>
<string name="orbot_install_dialog_content">Orbot moet geïnstalleerd en ingesteld zijn om verkeer erdoor te proxyen. Wil je het installeren?</string>
<string name="orbot_install_dialog_cancel">Annuleren?</string>
- <string name="orbot_install_dialog_ignore_tor">Gebruik Tor niet</string>
<!--StartOrbotDialogFragment strings-->
<string name="orbot_start_dialog_title">Orbot starten?</string>
- <string name="orbot_start_dialog_content">Orbot wordt niet uitgevoerd. Wil je het opstarten en verbinden met Tor?</string>
<string name="orbot_start_btn">Orbot starten</string>
<string name="orbot_start_dialog_start">Orbot starten</string>
<string name="orbot_start_dialog_cancel">Annuleren</string>
- <string name="orbot_start_dialog_ignore_tor">Gebruik Tor niet</string>
- <string name="user_id_no_name">&lt;no naam&gt;</string>
- <string name="none">&lt;geen&gt;</string>
<plurals name="n_keys">
<item quantity="one">1 sleutel</item>
<item quantity="other">%d sleutels</item>
@@ -230,7 +209,6 @@
<string name="no_filemanager_installed">Geen compatibele bestandsbeheerder geïnstalleerd.</string>
<string name="passphrases_do_not_match">De wachtwoorden komen niet overeen.</string>
<string name="passphrase_must_not_be_empty">Geef een wachtwoord in.</string>
- <string name="passphrase_for_symmetric_encryption">Symmetrische versleuteling.</string>
<string name="passphrase_for">Voer het wachtwoord in voor \'%s\'</string>
<string name="pin_for">Voer PIN in voor \'%s\'</string>
<string name="yubikey_pin_for">Voer PIN in om toegang te verkrijgen tot YubiKey voor \'%s\'</string>
@@ -249,7 +227,6 @@
<string name="specify_file_to_encrypt_to">Gelieve aan te geven naar welk bestand versleuteld moet worden.\nWAARSCHUWING: Als het bestand al bestaat, zal het overschreven worden!</string>
<string name="specify_file_to_decrypt_to">Gelieve aan te geven naar welk bestand ontsleuteld moet worden.\nWAARSCHUWING: Als het bestand al bestaat, zal het overschreven worden!</string>
<string name="key_deletion_confirmation_multi">Ben je zeker dat je alle geselecteerde sleutels wil verwijderen?</string>
- <string name="secret_key_deletion_confirmation">Na verwijderen zal je niet langer berichten versleuteld met deze sleutel kunnen lezen, en alle sleutelbevestigingen die ermee gedaan zijn verliezen!</string>
<string name="public_key_deletetion_confirmation">Sleutel \'%s\' verwijderen?</string>
<string name="also_export_secret_keys">Exporteer ook geheime sleutels</string>
<string name="reinstall_openkeychain">Je bent een gekende Android-bug tegengekomen. Gelieve OpenKeychain opnieuw te installeren als je je contacten met sleutels wil verbinden.</string>
@@ -258,7 +235,6 @@
<string name="no_keys_exported">Geen sleutels geëxporteerd.</string>
<string name="key_creation_el_gamal_info">Opmerking: alleen subsleutels ondersteunen ElGamal.</string>
<string name="key_not_found">Kan de sleutel %08X niet vinden.</string>
- <string name="specify_file_to_export_log_to">Gelieve aan te geven naar welk bestand geëxporteerd moet worden.\nWAARSCHUWING: Als het bestand al bestaat, zal het overschreven worden.</string>
<plurals name="bad_keys_encountered">
<item quantity="one">%d slechte geheime sleutel genegeerd. Misschien heb je geëxporteerd met de optie\n--export-secret-subkeys\nZorg ervoor dat je in plaats daarvan met --export-secret-keys exporteert.</item>
<item quantity="other">%d slechte geheime sleutels genegeerd. Misschien heb je geëxporteerd met de optie\n--export-secret-subkeys\nZorg ervoor dat je in plaats daarvan met --export-secret-keys exporteert.</item>
@@ -268,7 +244,6 @@
<string name="key_copied_to_clipboard">Sleutel is gekopieerd naar het klembord!</string>
<string name="fingerprint_copied_to_clipboard">Sleutel is gekopieerd naar het klembord!</string>
<string name="select_key_to_certify">Gelieve een sleutel te selecteren om te gebruiken voor bevestiging!</string>
- <string name="key_too_big_for_sharing">Sleutel is te groot om op deze manier gedeeld te worden!</string>
<string name="text_copied_to_clipboard">Tekst is gekopieerd naar klembord!</string>
<!--errors
no punctuation, all lowercase,
@@ -353,8 +328,8 @@
<string name="progress_encrypting">gegevens versleutelen…</string>
<string name="progress_decrypting">gegevens ontsleutelen…</string>
<string name="progress_preparing_signature">handtekening voorbereiden…</string>
- <string name="progress_generating_signature">handtekening genereren…</string>
<string name="progress_processing_signature">handtekening verwerken…</string>
+ <string name="progress_generating_signature">handtekening genereren…</string>
<string name="progress_verifying_signature">handtekening verifiëren…</string>
<string name="progress_signing">ondertekenen…</string>
<string name="progress_certifying">bezig met certificeren…</string>
@@ -366,14 +341,9 @@
<string name="progress_deleting">bezig met verwijderen van sleutels…</string>
<string name="progress_con_saving">consolidatie: bezig met opslaan naar cache…</string>
<string name="progress_con_reimport">consolidatie: bezig met opnieuw importeren…</string>
- <string name="progress_verifying_keyserver_url">bezig met verifiëren van sleutelserver…</string>
<!--action strings-->
<string name="hint_cloud_search_hint">Zoeken via naam, e-mail, ...</string>
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -403,7 +373,6 @@
<string name="help_about_version">Versie:</string>
<!--Import-->
<string name="import_tab_keyserver">Sleutelserver</string>
- <string name="import_tab_cloud">Zoeken</string>
<string name="import_tab_direct">Bestand/klembord</string>
<string name="import_tab_qr_code">QR code/NFC</string>
<string name="import_import">Geselecteerde sleutels importeren</string>
@@ -419,14 +388,6 @@
<string name="with_warnings">, met waarschuwingen</string>
<string name="with_cancelled">, tot annulatie</string>
<!--Import result toast-->
- <plurals name="import_keys_added_and_updated_1">
- <item quantity="one">Sleutel succesvol geïmporteerd</item>
- <item quantity="other">%1$d sleutels succesvol geïmporteerd</item>
- </plurals>
- <plurals name="import_keys_added_and_updated_2">
- <item quantity="one">en sleutel%2$s geüpdatet.</item>
- <item quantity="other">en %1$d sleutels%2$s.</item>
- </plurals>
<plurals name="import_keys_added">
<item quantity="one">Sleutel%2$s succesvol geïmporteerd.</item>
<item quantity="other">%1$d sleutels%2$s succesvol geïmporteerd.</item>
@@ -466,10 +427,6 @@
<string name="delete_cancelled">Verwijderen geannuleerd.</string>
<!--Revoke result toast (snackbar)-->
<!--Certify result toast-->
- <plurals name="certify_keys_ok">
- <item quantity="one">Sleutel%2$s succesvol gecertificeerd.</item>
- <item quantity="other">%1$d sleutels%2$s succesvol gecertificeerd.</item>
- </plurals>
<plurals name="certify_keys_with_errors">
<item quantity="one">Certificatie mislukt!</item>
<item quantity="other">Certificatie mislukt voor %d sleutels!</item>
@@ -531,7 +488,6 @@
</plurals>
<string name="key_list_empty_text1">Geen sleutels gevonden!</string>
<string name="key_list_filter_show_all">Alle sleutels weergeven</string>
- <string name="key_list_filter_show_certified">Enkel gecertificeerde sleutels weergeven</string>
<!--Key view-->
<string name="key_view_action_edit">Sleutel bewerken</string>
<string name="key_view_action_encrypt">Versleutel tekst</string>
@@ -548,23 +504,11 @@
<string name="key_view_tab_keybase">Keybase.io</string>
<string name="user_id_info_revoked_title">Ingetrokken</string>
<string name="user_id_info_revoked_text">Deze identiteit is door de sleuteleigenaar ingetrokken. Ze is niet langer geldig.</string>
- <string name="user_id_info_certified_title">Gecertificeerd</string>
- <string name="user_id_info_certified_text">Deze identiteit is door jou gecertificeerd.</string>
- <string name="user_id_info_uncertified_title">Niet gecertificeerd</string>
- <string name="user_id_info_uncertified_text">Deze identiteit is nog niet gecertificeerd. Je kan niet zeker zijn dat deze identiteit echt overeenkomt met een bepaald persoon.</string>
<string name="user_id_info_invalid_title">Ongeldig</string>
<string name="user_id_info_invalid_text">Er is iets mis met deze identiteit!</string>
<!--Key trust-->
- <string name="key_trust_already_verified">Je hebt deze sleutel al bevestigd!</string>
- <string name="key_trust_it_is_yours">Dit is een van jouw sleutels!</string>
- <string name="key_trust_maybe">Deze sleutel is ingetrokken noch verlopen.\nJe hebt ze niet bevestigd, maar je kan kiezen ze te vertrouwen.</string>
- <string name="key_trust_revoked">Deze sleutel is door de eigenaar ingetrokken. Je zou ze niet moeten vertrouwen.</string>
- <string name="key_trust_expired">Deze sleutel is verlopen. Je zou ze niet moeten vertrouwen.</string>
- <string name="key_trust_old_keys">Het kan oké zijn deze sleutel te gebruiken om een oud bericht te ontsleutelen van een moment waarop de sleutel nog geldig was.</string>
- <string name="key_trust_no_cloud_evidence">Geen bewijs van de cloud voor de betrouwbaarheid van deze sleutel.</string>
<string name="key_trust_start_cloud_search">Zoeken starten</string>
<string name="key_trust_results_prefix">Keybase.io geeft “bewijzen” die stellen dat de eigenaar van deze sleutel:</string>
- <string name="key_trust_header_text">Let op: Keybase.io-bewijzen zijn een experimentele functie van OpenKeychain. We moedigen je aan QR-codes te scannen of sleutels uit te wisselen via NFC bovenop het bevestigen ervan.</string>
<!--keybase proof stuff-->
<string name="keybase_proof_failure">Helaas kan dit bewijs niet geverifieerd worden.</string>
<string name="keybase_unknown_proof_failure">Niet-herkend probleem met de bewijschecker</string>
@@ -614,7 +558,6 @@
<string name="edit_key_error_bad_nfc_size">Sleutelgrootte wordt niet ondersteund door smartcard!</string>
<string name="edit_key_error_bad_nfc_stripped">Kan sleutel niet verplaatsen naar smartcard (ofwel gestript ofwel \'doorschakelen-naar-kaart\')!</string>
<!--Create key-->
- <string name="create_key_upload">Synchroniseren met de cloud</string>
<string name="create_key_empty">Dit veld moet ingevuld worden</string>
<string name="create_key_passphrases_not_equal">Wachtwoorden komen niet overeen</string>
<string name="create_key_final_text">Je hebt volgende identiteit ingevoerd:</string>
@@ -630,12 +573,9 @@
<string name="create_key_add_email_text">Bijkomstige e-mailadressen zijn ook verbonden met deze sleutel en kunnen gebruikt worden voor veilige communicatie.</string>
<string name="create_key_email_already_exists_text">E-mailadres is al toegevoegd</string>
<string name="create_key_email_invalid_email">E-mailadresformaat is ongeldig</string>
- <string name="create_key_yubi_key_pin_text">Onthou deze PIN, ze is nodig om je YubiKey later te gebruiken. Schrijf indien mogelijk de administrator-PIN ergens op en bewaar deze op een veilige plek.</string>
<string name="create_key_yubi_key_pin">PIN</string>
<string name="create_key_yubi_key_admin_pin">Administrator-PIN</string>
- <string name="create_key_yubi_key_pin_repeat_text">Voer de PIN en administrator-PIN in om door te gaan.</string>
<string name="create_key_yubi_key_pin_repeat">Herhaal PIN</string>
- <string name="create_key_yubi_key_admin_pin_repeat">Herhaal administrator-PIN</string>
<string name="create_key_yubi_key_pin_not_correct">PIN is niet correct!</string>
<!--View key-->
<string name="view_key_revoked">Ingetrokken: sleutel mag niet meer gebruikt worden!</string>
@@ -648,10 +588,8 @@
<!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Sleutelserver toevoegen</string>
<string name="edit_keyserver_dialog_title">Sleutelserver bewerken</string>
- <string name="add_keyserver_verified">Sleutelserver geverifieerd!</string>
<string name="add_keyserver_without_verification">Sleutelserver toegevoegd zonder verificatie.</string>
<string name="add_keyserver_invalid_url">Ongeldige URL!</string>
- <string name="add_keyserver_connection_failed">Kon niet verbinden met sleutelserver. Controleer de URL en je internetverbinding.</string>
<string name="keyserver_preference_deleted">%s verwijderd</string>
<string name="keyserver_preference_cannot_delete_last">Kan laatste sleutelserver niet verwijderen, er is er minstens één nodig!</string>
<!--Navigation Drawer-->
@@ -710,7 +648,6 @@
<string name="msg_ip_master_flags_xxxa">Hoofdvlaggen: authenticeren</string>
<string name="msg_ip_master_flags_xxxx">Hoofdvlaggen: geen</string>
<string name="msg_ip_merge_public">Bezig met samenvoegen van geïmporteerde gegevens in bestaande publieke sleutelbos</string>
- <string name="msg_ip_merge_secret">Bezig met samenvoegen van geïmporteerde gegevens in bestaande publieke sleutelbos</string>
<string name="msg_ip_subkey">Bezig met verwerken van subsleutel %s</string>
<string name="msg_ip_subkey_expired">Subsleutel is vervallen op %s</string>
<string name="msg_ip_subkey_expires">Subsleutel vervalt op %s</string>
@@ -776,7 +713,6 @@
<string name="msg_is_importing_subkeys">Bezig met verwerken van geheime subsleutels</string>
<string name="msg_is_error_io_exc">Fout bij coderen van sleutelbos</string>
<string name="msg_is_merge_public">Bezig met samenvoegen van geïmporteerde gegevens in bestaande publieke sleutelbos</string>
- <string name="msg_is_merge_secret">Bezig met samenvoegen van geïmporteerde gegevens in bestaande publieke sleutelbos</string>
<string name="msg_is_merge_special">Bezig met samenvoegen van gegevens van self-certificaten uit publieke sleutelbos</string>
<string name="msg_is_pubring_generate">Bezig met aanmaken van publieke sleutelbos uit geheime sleutelbos</string>
<string name="msg_is_subkey_nonexistent">Subsleutel %s niet beschikbaar in geheime sleutel</string>
@@ -877,7 +813,6 @@
<string name="msg_cr_error_no_user_id">Sleutelbossen moeten met minstens een gebruikers-ID aangemaakt worden!</string>
<string name="msg_cr_error_no_certify">Hoofdsleutel moet certificeer-vlag hebben!</string>
<string name="msg_cr_error_null_expiry">Verloopdatum kan niet hetzelfde als voordien zijn bij aanmaken van een sleutel. Dit is een bug, gelieve een verslag in te dienen!</string>
- <string name="msg_cr_error_keysize_512">Sleutelgrootte moet groter dan of gelijk zijn aan 512!</string>
<string name="msg_cr_error_no_curve">Geen sleutelgrootte opgegeven! Dit is een bug, gelieve een verslag in te dienen!</string>
<string name="msg_cr_error_no_keysize">Geen elliptische curve opgegeven! Dit is een bug, gelieve een verslag in te dienen!</string>
<string name="msg_cr_error_internal_pgp">Interne OpenPGP-fout!</string>
@@ -1035,8 +970,6 @@
<string name="msg_dc_unlocking">Bezig met ontgrendelen van geheime sleutel</string>
<!--Messages for VerifySignedLiteralData operation-->
<string name="msg_vl">Ondertekeningscontrole wordt gestart</string>
- <string name="msg_vl_error_no_siglist">Geen ondertekeningslijst in ondertekende letterlijke gegevens</string>
- <string name="msg_vl_error_wrong_key">Bericht niet ondertekend met de juiste sleutel</string>
<string name="msg_vl_error_missing_literal">Geen payload in ondertekende letterlijke gegevens</string>
<string name="msg_vl_clear_meta_file">Bestandsnaam: %s</string>
<string name="msg_vl_clear_meta_mime">MIME-type: %s</string>
@@ -1056,7 +989,6 @@
<string name="msg_se_success">Ondertekening/versleuteling geslaagd</string>
<!--Messages for PgpSignEncrypt operation-->
<string name="msg_pse_asymmetric">Bezig met publieke sleutels voorbereiden voor versleuteling</string>
- <string name="msg_pse_clearsign_only">Ondertekenen van platte tekst-input wordt niet ondersteund!</string>
<string name="msg_pse_compressing">Bezig met voorbereiden van comprimeren</string>
<string name="msg_pse_encrypting">Bezig met versleutelen van gegevens</string>
<string name="msg_pse_error_bad_passphrase">Wachtwoord verkeerd!</string>
@@ -1112,37 +1044,15 @@
<string name="msg_import_fetch_error_decode">Fout bij decoderen van opgehaalde sleutelbos!</string>
<string name="msg_import_fetch_error">Sleutel kon niet opgehaald worden! (Netwerkproblemen?)</string>
<string name="msg_import_fetch_keybase">Bezig met ophalen van keybase.io: %s</string>
- <string name="msg_import_fetch_error_keyserver">Kon sleutel niet ophalen van sleutelservers: %s</string>
<string name="msg_import_fetch_keyserver">Bezig met ophalen van sleutelserver: %s</string>
<string name="msg_import_fetch_keyserver_ok">Ophalen van sleutel geslaagd!</string>
<string name="msg_import_keyserver">Sleutelserver %s wordt gebruikt</string>
- <string name="msg_import_fingerprint_error">Vingerafdruk van opgehaalde sleutel komt niet overeen met verwachte vingerafdruk!</string>
- <string name="msg_import_fingerprint_ok">Vingerafdrukcontrole OKÉ</string>
<string name="msg_import_merge">Bezig met samenvoegen van opgehaalde gegevens</string>
<string name="msg_import_merge_error">Fout bij samenvoegen van opgehaalde gegevens!</string>
<string name="msg_import_error">Importeren mislukt!</string>
<string name="msg_import_error_io">Importeren mislukt door i/o-fout!</string>
<string name="msg_import_partial">Importeren geslaagd, met fouten!</string>
<string name="msg_import_success">Importeren geslaagd!</string>
- <plurals name="msg_export">
- <item quantity="one">Bezig met exporteren van een sleutel</item>
- <item quantity="other">Bezig met exporteren van %d sleutels</item>
- </plurals>
- <string name="msg_export_all">Bezig met exporteren van alle sleutels</string>
- <string name="msg_export_public">Bezig met exporteren van publieke sleutel %s</string>
- <string name="msg_export_upload_public">Bezig met uploaden van publieke sleutel %s</string>
- <string name="msg_export_secret">Bezig met exporteren van geheime sleutel %s</string>
- <string name="msg_export_error_no_file">Geen bestandsnaam opgegeven!</string>
- <string name="msg_export_error_fopen">Fout bij openen van bestand!</string>
- <string name="msg_export_error_no_uri">Geen URI opgegeven!</string>
- <string name="msg_export_error_uri_open">Fout bij openen van URI stream!</string>
- <string name="msg_export_error_storage">Opslag is niet klaar voor schrijven!</string>
- <string name="msg_export_error_db">Databasefout!</string>
- <string name="msg_export_error_io">Input/output-fout!</string>
- <string name="msg_export_error_key">Fout bij voorwerken van sleutelgegevens!</string>
- <string name="msg_export_error_upload">Fout bij uploaden van sleutel naar server! Controleer je internetverbinding</string>
- <string name="msg_export_success">Exporteren geslaagd</string>
- <string name="msg_export_upload_success">Uploaden naar sleutelserver geslaagd</string>
<string name="msg_del_error_empty">Niets om te verwijderen!</string>
<string name="msg_del_error_multi_secret">Geheime sleutels kunnen enkel individueel verwijderd worden!</string>
<plurals name="msg_del">
@@ -1160,6 +1070,7 @@
<item quantity="one">Verwijderen van een sleutel mislukt</item>
<item quantity="other">Verwijderen van %d sleutels mislukt</item>
</plurals>
+ <!--Linked Identity verification-->
<string name="msg_acc_saved">Account opgeslaan</string>
<string name="msg_download_success">Succesvol gedownload!</string>
<string name="msg_download_no_valid_keys">Geen geldige sleutels gevonden in bestand/klembord!</string>
@@ -1180,12 +1091,7 @@
<string name="msg_keybase_error_dns_fail">DNS TXT record ophalen mislukt</string>
<string name="msg_keybase_error_specific">%s</string>
<string name="msg_keybase_error_msg_payload_mismatch">Ontsleuteld bewijs komt niet overeen met verwachte waarde</string>
- <!--Messages for Export Log operation-->
- <string name="msg_export_log_start">Bezig met exporteren van log</string>
- <string name="msg_export_log_error_fopen">Fout bij openen van bestand</string>
- <string name="msg_export_log_error_no_file">Geen bestandsnaam opgegeven!</string>
- <string name="msg_export_log_error_writing">I/O-fout bij schrijven naar bestand!</string>
- <string name="msg_export_log_success">Log succesvol geëxporteerd!</string>
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<string name="passp_cache_notif_click_to_clear">Tik om wachtwoorden te wissen.</string>
<plurals name="passp_cache_notif_n_keys">
@@ -1210,13 +1116,10 @@
<string name="section_certifier_id">Certificeer</string>
<string name="section_cert">Certificaat Details</string>
<string name="label_user_id">Identiteit</string>
- <string name="unknown_uid">&lt;onbekend&gt;</string>
<string name="empty_certs">Geen certificaten voor deze sleutel</string>
<string name="certs_text">Enkel gevalideerde self-certificaten en gevalideerde certificaten gemaakt met jouw sleutels worden hier weergegeven.</string>
<string name="section_uids_to_certify">Identiteiten voor</string>
<string name="certify_text">De sleutels die je importeert bevatten \'identiteiten\': namen en e-mailadressen. Selecteer precies die voor bevestiging die overeenkomen met wat je had verwacht.</string>
- <string name="certify_fingerprint_text">Vergelijk de weergegeven vingerafdruk, karakter per karakter, met die weergegeven op het toestel van je partner.</string>
- <string name="certify_fingerprint_text2">Komen de weergegeven vingerafdrukken overeen?</string>
<string name="label_revocation">Intrek Reden</string>
<string name="label_cert_type">Type</string>
<string name="error_key_not_found">Sleutel niet gevonden!</string>
@@ -1274,7 +1177,6 @@
<string name="button_bind_key">Sleutel binden</string>
<string name="yubikey_serno">Serienummer: %s</string>
<string name="yubikey_key_holder">Sleutelhouder:</string>
- <string name="yubikey_key_holder_not_set">Sleutelhouder: &lt;niet ingesteld&gt;</string>
<string name="yubikey_status_bound">YubiKey komt overeen en is gebonden aan sleutel</string>
<string name="yubikey_status_unbound">YubiKey komt overeen en kan worden gebonden aan sleutel</string>
<string name="yubikey_status_partly">YubiKey komt overeen en is gedeeltelijk gebonden aan sleutel</string>
@@ -1294,7 +1196,6 @@
<string name="error_nfc_data_not_found">Sleutel of object niet gevonden.</string>
<string name="error_nfc_unknown">Onbekende fout</string>
<string name="error_nfc_try_again">Opnieuw proberen</string>
- <string name="error_pin_nodefault">Standaard-PIN geweigerd!</string>
<string name="error_temp_file">Fout bij aanmaken van tijdelijk bestand.</string>
<string name="btn_delete_original">Oorspronkelijk bestand verwijderen</string>
<string name="snack_encrypt_filenames_on">Bestandsnamen <b>zijn</b> versleuteld.</string>
@@ -1306,8 +1207,6 @@
<string name="error_loading_keys">Fout bij laden van sleutels!</string>
<string name="error_empty_log">(fout, leeg log)</string>
<string name="error_reading_text">Kon invoer niet lezen om te ontsleutelen!</string>
- <string name="filename_unknown">&lt;geen bestandsnaam&gt;</string>
- <string name="filename_unknown_text">&lt;platte tekstgegevens&gt;</string>
<string name="intent_show">Toon ondertekende/versleutelde inhoud</string>
<string name="view_internal">Bekijken in OpenKeychain</string>
<string name="error_preparing_data">Fout bij voorbereiden van gegevens!</string>
@@ -1323,4 +1222,5 @@
<string name="error_scan_fp">Fout bij scannen van vingerafdruk!</string>
<string name="error_scan_match">Vingerafdrukken komen niet overeen!</string>
<string name="error_expiry_past">Verloopdatum is in het verleden!</string>
+ <!--Other Linked Identity strings-->
</resources>
diff --git a/OpenKeychain/src/main/res/values-pl/strings.xml b/OpenKeychain/src/main/res/values-pl/strings.xml
index bf46e5c42..35d01dc11 100644
--- a/OpenKeychain/src/main/res/values-pl/strings.xml
+++ b/OpenKeychain/src/main/res/values-pl/strings.xml
@@ -30,7 +30,6 @@
<!--section-->
<string name="section_user_ids">Tożsamości</string>
<string name="section_keys">Pod-klucze</string>
- <string name="section_cloud_search">Szukanie w Chmurze</string>
<string name="section_certify">Zatwierdź</string>
<string name="section_actions">Działania</string>
<string name="section_share_key">Klucz</string>
@@ -71,9 +70,7 @@
<string name="label_file_ascii_armor">Włącz ASCII Armor</string>
<string name="label_write_version_header">Niech inni wiedzą, że używasz OpenKeychain</string>
<string name="label_write_version_header_summary">Wpisuje \'\'OpenKeychain v2.7\' do podpisów, szyfrogramów i wyeksportowanych kluczy OpenPGP.</string>
- <string name="label_use_default_yubikey_pin">Użyj domyślnego PIN-u YubiKey</string>
<string name="label_use_num_keypad_for_yubikey_pin">Użyj klawiatury numerycznej dla PIN-u YubiKey</string>
- <string name="label_label_use_default_yubikey_pin_summary">Używa domyślnego PIN-u (123456) do dostępu do YubiKeys przez NFC</string>
<string name="label_to">Szyfruj do:</string>
<string name="label_delete_after_decryption">Usuń po odszyfrowaniu</string>
<string name="label_encryption_algorithm">Algorytm szyfrowania</string>
@@ -89,7 +86,6 @@
<string name="label_name">Imię</string>
<string name="label_comment">Komentarz</string>
<string name="label_email">Adres email</string>
- <string name="label_send_key">Synchronizuj z chmurą</string>
<string name="label_fingerprint">Odcisk</string>
<string name="expiry_date_dialog_title">Ustaw datę wygaśnięcia</string>
<string name="label_preferred">preferowany</string>
@@ -99,8 +95,6 @@
<!--OrbotHelper strings-->
<!--InstallDialogFragment strings-->
<!--StartOrbotDialogFragment strings-->
- <string name="user_id_no_name">&lt;bez nazwy&gt;</string>
- <string name="none">&lt;żaden&gt;</string>
<plurals name="n_keys">
<item quantity="one">1 klucz</item>
<item quantity="few">%d klucze</item>
@@ -141,7 +135,6 @@
<string name="flag_authenticate">Uwierzytelniaj</string>
<!--sentences-->
<string name="no_filemanager_installed">Nie zainstalowano żadnego kompatybilnego menadżera plików.</string>
- <string name="passphrase_for_symmetric_encryption">Szyfrowanie symetryczne.</string>
<string name="pin_for">Wpisz PIN dla \'%s\'</string>
<string name="encrypt_sign_successful">Pomyślnie podpisano i/lub zaszyfrowano.</string>
<string name="encrypt_sign_clipboard_successful">Pomyslnie podpisano i/lub zaszyfrowano do schowka.</string>
@@ -162,7 +155,6 @@
<string name="nfc_successful">Pomyślnie wysłano klucz przez NFC Beam!</string>
<string name="key_copied_to_clipboard">Klucz został skopiowany do schowka!</string>
<string name="fingerprint_copied_to_clipboard">Odcisk klucza został skopiowany do schowka!</string>
- <string name="key_too_big_for_sharing">Klucz ma za duży rozmiar by być udostępniony w ten sposób!</string>
<string name="text_copied_to_clipboard">Tekst został skopiowany do schowka!</string>
<!--errors
no punctuation, all lowercase,
@@ -227,8 +219,8 @@
<string name="progress_encrypting">szyfrowanie danych...</string>
<string name="progress_decrypting">deszyfrowywanie danych...</string>
<string name="progress_preparing_signature">przygotowywanie podpisu...</string>
- <string name="progress_generating_signature">generowanie podpisu...</string>
<string name="progress_processing_signature">przetwarzanie podpisu...</string>
+ <string name="progress_generating_signature">generowanie podpisu...</string>
<string name="progress_verifying_signature">weryfikowanie podpisu...</string>
<string name="progress_signing">podpisywanie...</string>
<string name="progress_certifying">certyfikowanie...</string>
@@ -240,10 +232,6 @@
<string name="progress_deleting">usuwanie kluczy...</string>
<!--action strings-->
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -272,7 +260,6 @@
<string name="help_about_version">Wersja:</string>
<!--Import-->
<string name="import_tab_keyserver">Serwery kluczy</string>
- <string name="import_tab_cloud">Szukaj w chmurze</string>
<string name="import_tab_direct">Plik/Schowek</string>
<string name="import_tab_qr_code">Kod QR/NFC</string>
<string name="import_import">Zaimportuj wybrane klucze</string>
@@ -284,16 +271,6 @@
<string name="with_warnings">, z ostrzeżeniami</string>
<string name="with_cancelled">, aż anulowano</string>
<!--Import result toast-->
- <plurals name="import_keys_added_and_updated_1">
- <item quantity="one">Pomyślnie zaimportowano klucz</item>
- <item quantity="few">Pomyślnie zaimportowano %1$d kluczy</item>
- <item quantity="other">Pomyślnie zaimportowano %1$d kluczy</item>
- </plurals>
- <plurals name="import_keys_added_and_updated_2">
- <item quantity="one">oraz zaktualizowano klucz %2$s.</item>
- <item quantity="few">oraz zaktualizowano %1$d kluczy%2$s.</item>
- <item quantity="other">oraz zaktualizowano %1$d kluczy%2$s.</item>
- </plurals>
<plurals name="import_keys_added">
<item quantity="one">Pomyślnie zaimportowano klucz%2$s.</item>
<item quantity="few">Pomyślnie zaimportowano %1$d kluczy%2$s.</item>
@@ -341,11 +318,6 @@
<string name="delete_cancelled">Operacja usuwania anulowana.</string>
<!--Revoke result toast (snackbar)-->
<!--Certify result toast-->
- <plurals name="certify_keys_ok">
- <item quantity="one">Pomyślnie certyfikowano klucz%2$s.</item>
- <item quantity="few">Pomyślnie certyfikowano %1$d kluczy%2$s.</item>
- <item quantity="other">Pomyślnie certyfikowano %1$d kluczy%2$s.</item>
- </plurals>
<plurals name="certify_keys_with_errors">
<item quantity="one">Certyfikacja nie powiodła się!</item>
<item quantity="few">Nie udana certyfikacja dla %d kluczy!</item>
@@ -399,7 +371,6 @@ OSTRZEŻENIE: Jeżeli nie wiesz, czemu wyświetlił się ten komunikat, nie zezw
</plurals>
<string name="key_list_empty_text1">Nie znaleziono kluczy!</string>
<string name="key_list_filter_show_all">Pokaż wszystkie klucze</string>
- <string name="key_list_filter_show_certified">Pokaż tylko certyfikowane klucze</string>
<!--Key view-->
<string name="key_view_action_edit">Edytuj klucz</string>
<string name="key_view_action_encrypt">Szyfruj tekst</string>
@@ -414,10 +385,6 @@ OSTRZEŻENIE: Jeżeli nie wiesz, czemu wyświetlił się ten komunikat, nie zezw
<string name="key_view_tab_certs">Certyfikaty</string>
<string name="user_id_info_revoked_title">Unieważnione</string>
<string name="user_id_info_revoked_text">Ta tożsamość została unieważniona przez właściciela klucza. Nie jest ona już ważna.</string>
- <string name="user_id_info_certified_title">Certyfikowane</string>
- <string name="user_id_info_certified_text">Ta tożsamość była certyfikowana przez Ciebie.</string>
- <string name="user_id_info_uncertified_title">Nie certyfikowana</string>
- <string name="user_id_info_uncertified_text">Ta tożsamość nie była jeszcze certyfikowana. Nie możesz być pewny, że ta tożsamość naprawdę jest tą osobą za którą się podaje.</string>
<string name="user_id_info_invalid_title">Nieprawidłowe</string>
<string name="user_id_info_invalid_text">Coś jest nie tak z tą tożsamością!</string>
<!--Key trust-->
@@ -440,7 +407,6 @@ OSTRZEŻENIE: Jeżeli nie wiesz, czemu wyświetlił się ten komunikat, nie zezw
<string name="edit_key_error_add_identity">Dodaj przynajmniej jedną tożsamość!</string>
<string name="edit_key_error_add_subkey">Dodaj przynajmniej jeden pod-klucz!</string>
<!--Create key-->
- <string name="create_key_upload">Synchronizuj z chmurą</string>
<string name="create_key_empty">Dane pole jest wymagane</string>
<string name="create_key_final_text">Wpisałeś następującą tożsamość:</string>
<string name="create_key_final_robot_text">Tworzenie klucza może zająć trochę czasu... w międzyczasie idź się napij kawy.</string>
@@ -532,9 +498,6 @@ OSTRZEŻENIE: Jeżeli nie wiesz, czemu wyświetlił się ten komunikat, nie zezw
<item quantity="other">Importowanie %d kluczy</item>
</plurals>
<string name="msg_import_error">Operacja importowania nie udała się!</string>
- <string name="msg_export_error_storage">Dysk nie jest gotowy do zapisu!</string>
- <string name="msg_export_error_db">Błąd bazy danych!</string>
- <string name="msg_export_success">Operacja eksportu zakończona pomyślnie</string>
<string name="msg_del_error_empty">Nie ma nic do usunięcia!</string>
<string name="msg_del_error_multi_secret">Klucze prywatne mogą być usuwane tylko pojedynczo!</string>
<plurals name="msg_del">
@@ -554,6 +517,7 @@ OSTRZEŻENIE: Jeżeli nie wiesz, czemu wyświetlił się ten komunikat, nie zezw
<item quantity="few">Nie udało się usunąć %d kluczy</item>
<item quantity="other">Nie udało się usunąć %d kluczy</item>
</plurals>
+ <!--Linked Identity verification-->
<string name="msg_acc_saved">Zapisano konto</string>
<string name="msg_download_success">Pobrano pomyślnie!</string>
<plurals name="error_import_non_pgp_part">
@@ -562,7 +526,7 @@ OSTRZEŻENIE: Jeżeli nie wiesz, czemu wyświetlił się ten komunikat, nie zezw
<item quantity="other">Część wczytanego pliku to poprawne obiekty OpenPGP, ale nie są kluczami OpenPGP</item>
</plurals>
<!--Messages for Keybase Verification operation-->
- <!--Messages for Export Log operation-->
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<!--Keyserver sync-->
<!--First Time-->
@@ -572,7 +536,6 @@ OSTRZEŻENIE: Jeżeli nie wiesz, czemu wyświetlił się ten komunikat, nie zezw
<string name="section_certifier_id">Certyfikujący</string>
<string name="section_cert">Szczegóły certyfikatu</string>
<string name="label_user_id">Tożsamość</string>
- <string name="unknown_uid">&lt;nieznany&gt;</string>
<string name="empty_certs">Nie ma certyfikatów dla tego klucza</string>
<string name="section_uids_to_certify">Tożsamości dla</string>
<string name="label_revocation">Powód odwołania</string>
@@ -596,4 +559,5 @@ OSTRZEŻENIE: Jeżeli nie wiesz, czemu wyświetlił się ten komunikat, nie zezw
<!--TODO: rename all the things!-->
<!--<string name="enter_passphrase_twice">Enter password twice</string>-->
<!--<string name="nfc_text">Please place a NFC tag near your device</string>-->
+ <!--Other Linked Identity strings-->
</resources>
diff --git a/OpenKeychain/src/main/res/values-ru/strings.xml b/OpenKeychain/src/main/res/values-ru/strings.xml
index 55a5afa5e..8db2e64ae 100644
--- a/OpenKeychain/src/main/res/values-ru/strings.xml
+++ b/OpenKeychain/src/main/res/values-ru/strings.xml
@@ -9,6 +9,7 @@
<string name="title_decrypt">Расшифровать</string>
<string name="title_add_subkey">Добавить подключ</string>
<string name="title_edit_key">Изменить ключ</string>
+ <string name="title_linked_create">Создать связанный идентификатор</string>
<string name="title_preferences">Настройки</string>
<string name="title_api_registered_apps">Приложения</string>
<string name="title_key_server_preference">Серверы OpenPGP</string>
@@ -24,6 +25,7 @@
<string name="title_export_keys">Резервные ключи</string>
<string name="title_key_not_found">Ключ не найден</string>
<string name="title_send_key">Загрузить на сервер ключей</string>
+ <string name="title_backup">Резервировать ключ</string>
<string name="title_certify_key">Сертифицировать ключ</string>
<string name="title_key_details">Сведения о ключе</string>
<string name="title_help">Помощь</string>
@@ -31,24 +33,30 @@
<string name="title_exchange_keys">Обмен ключами</string>
<string name="title_advanced_key_info">Дополнительные сведения</string>
<string name="title_delete_secret_key">Удалить ВАШ ключ \'%s\'?</string>
- <string name="title_export_log">Экспорт журнала</string>
<string name="title_manage_my_keys">Управление ключами</string>
<!--section-->
<string name="section_user_ids">Идентификаторы</string>
<string name="section_yubikey">YubiKey</string>
<string name="section_linked_system_contact">Связанные контакты</string>
+ <string name="section_keybase_proofs">Доказательства Keybase.io</string>
<string name="section_should_you_trust">Должны ли Вы доверять этому ключу?</string>
<string name="section_proof_details">Подтвердить верификацию</string>
- <string name="section_cloud_evidence">Подтвердить из облака</string>
<string name="section_keys">Доп. ключи</string>
- <string name="section_cloud_search">Облачный поиск</string>
- <string name="section_proxy_settings">Настройки прокси</string>
+ <string name="section_cloud_search">Поиск ключа</string>
+ <string name="section_cloud_search_summary">Сервер ключей, keybase.io</string>
+ <string name="section_passphrase_cache">Пароли и PIN-коды</string>
+ <string name="section_proxy_settings">Сетевая анонимность</string>
+ <string name="section_proxy_settings_summary">Tor, настройки прокси</string>
<string name="section_gui">Интерфейс</string>
+ <string name="section_sync_settings">Синхронизация</string>
+ <string name="section_sync_settings_summary">Автоматическое обновление ключей, </string>
+ <string name="section_experimental_features">Экспериментальные возможности</string>
<string name="section_certify">Подтвердить</string>
<string name="section_actions">Действия</string>
<string name="section_share_key">Ключ</string>
<string name="section_key_server">Сервер ключей</string>
<string name="section_fingerprint">Отпечаток ключа</string>
+ <string name="section_phrases">Фразы</string>
<string name="section_encrypt">Зашифровать</string>
<string name="section_decrypt">Расшифровка / Подтверждение</string>
<string name="section_current_expiry">Текущий срок годности</string>
@@ -69,12 +77,14 @@
<string name="btn_back">Назад</string>
<string name="btn_no">Нет</string>
<string name="btn_match">Отпечатки совпадают</string>
- <string name="btn_share_encrypted_signed">Зашифровать и отправить текст</string>
- <string name="btn_copy_encrypted_signed">Зашифровать и скопировать текст</string>
+ <string name="btn_match_phrases">Совпадающие фразы</string>
+ <string name="btn_share_encrypted_signed">Зашифровать/подписать и поделиться текстом</string>
+ <string name="btn_copy_encrypted_signed">Зашифровать/подписать и скопировать текст</string>
<string name="btn_view_cert_key">Просмотр ключа</string>
<string name="btn_create_key">Создать ключ</string>
<string name="btn_add_files">Добавить файл(ы)</string>
- <string name="btn_share_decrypted_text">Отправить расшифрованный текст</string>
+ <string name="btn_share_decrypted_text">Опубликовать</string>
+ <string name="btn_open_with">Открыть с помощью...</string>
<string name="btn_copy_decrypted_text">Копировать расшифрованный текст</string>
<string name="btn_decrypt_clipboard">Прочитать из буфера</string>
<string name="btn_decrypt_files">Выберите входной файл</string>
@@ -85,10 +95,11 @@
<string name="btn_add_keyserver">Добавить</string>
<string name="btn_save_default">Сохранить по умолчанию</string>
<string name="btn_saved">Сохранено!</string>
+ <string name="btn_not_matching">Нет совпадений</string>
<!--menu-->
<string name="menu_preferences">Настройки</string>
<string name="menu_help">Помощь</string>
- <string name="menu_export_key">Поместить резервную копию в файл</string>
+ <string name="menu_export_key">Резервировать ключ</string>
<string name="menu_delete_key">Удалить ключ</string>
<string name="menu_manage_keys">Управление ключами</string>
<string name="menu_search">Поиск</string>
@@ -99,8 +110,9 @@
<string name="menu_export_all_keys">Экспорт всех ключей</string>
<string name="menu_update_all_keys">Обновить все ключи</string>
<string name="menu_advanced">Дополнительные сведения</string>
- <string name="menu_certify_fingerprint">Подтвердить по отпечатку</string>
- <string name="menu_export_log">Экспорт журнала</string>
+ <string name="menu_certify_fingerprint">Подтвердить через отпечаток</string>
+ <string name="menu_certify_fingerprint_phrases">Подтвердить фразами</string>
+ <string name="menu_share_log">Опубликовать отчёт</string>
<string name="menu_keyserver_add">Добавить</string>
<!--label-->
<string name="label_message">Текст</string>
@@ -117,9 +129,7 @@
<string name="label_file_ascii_armor">Использовать ASCII формат</string>
<string name="label_write_version_header">Добавить комментарий об использовании OpenKeychain</string>
<string name="label_write_version_header_summary">Дописывать \'OpenKeychain v2.x\' в OpenPGP подписи, шифры, и экспортируемые ключи</string>
- <string name="label_use_default_yubikey_pin">Использовать YubiKey PIN по умолчанию</string>
<string name="label_use_num_keypad_for_yubikey_pin">Использовать цифровую клавиатуру для YubiKey PIN</string>
- <string name="label_label_use_default_yubikey_pin_summary">Использовать PIN по умолчанию (123456) для доступа к YubiKeys через NFC</string>
<string name="label_asymmetric_from">Подписать:</string>
<string name="label_to">Зашифровать для:</string>
<string name="label_delete_after_encryption">Удалить файлы после шифрования</string>
@@ -128,6 +138,7 @@
<string name="label_hash_algorithm">ХЭШ-алгоритм</string>
<string name="label_symmetric">Зашифровать с паролем</string>
<string name="label_passphrase_cache_ttl">Запомнить время</string>
+ <string name="label_passphrase_cache_subs">Запомнить пароли для подключей</string>
<string name="label_message_compression">Сжатие текста</string>
<string name="label_file_compression">Сжатие файла</string>
<string name="label_keyservers">Выберите серверы OpenPGP</string>
@@ -142,7 +153,7 @@
<string name="label_name">Имя</string>
<string name="label_comment">Комментарий</string>
<string name="label_email">Email</string>
- <string name="label_send_key">Синхронизировать с облаком</string>
+ <string name="label_send_key">Синхронизация с Интернет</string>
<string name="label_fingerprint">Отпечаток</string>
<string name="expiry_date_dialog_title">Срок годности</string>
<string name="label_keyservers_title">Серверы ключей</string>
@@ -152,15 +163,30 @@
<string name="label_enable_compression">Использовать сжатие</string>
<string name="label_encrypt_filenames">Шифровать имена файлов</string>
<string name="label_hidden_recipients">Скрыть получателей</string>
- <string name="label_verify_keyserver">Подтвердить сервер ключей</string>
- <string name="label_enter_keyserver_url">Введите адрес сервера ключей</string>
+ <string name="label_verify_keyserver_connection">Тест соединения</string>
+ <string name="label_only_trusted_keyserver">Только доверенные сервера ключей</string>
<string name="label_keyserver_dialog_delete">Удалить сервер ключей</string>
<string name="label_theme">Тема</string>
<string name="pref_keyserver">Серверы OpenPGP</string>
<string name="pref_keyserver_summary">Искать ключи на выбранных серверах OpenPGP (протокол HKP)</string>
<string name="pref_keybase">keybase.io</string>
<string name="pref_keybase_summary">Искать ключи на Keybase.io</string>
+ <string name="label_sync_settings_keyserver_title">Автоматически обновлять ключи</string>
+ <string name="label_sync_settings_keyserver_summary_on">Ключи старше недели обновляются с предпочтительного сервера ключей</string>
+ <string name="label_sync_settings_keyserver_summary_off">Ключи не обновляются автоматически</string>
+ <string name="label_sync_settings_contacts_title">Связать ключи с контактами</string>
+ <string name="label_sync_settings_contacts_summary_on">Связывать ключи с контактами основываясь на именах и адресах электронной почты. Это происходит полностью в автономном режиме на вашем устройстве.</string>
+ <string name="label_sync_settings_contacts_summary_off">Новые ключи не будут связаны с контактами</string>
<!--label shown in Android settings under the OpenKeychain account-->
+ <string name="keyserver_sync_settings_title">Автоматически обновлять ключи</string>
+ <string name="label_experimental_settings_desc_title">Предупреждение</string>
+ <string name="label_experimental_settings_desc_summary">Эти новые возможности ещё не закончены и/или пока только изучаются. Проще говоря, не стоит полагаться на их безопасность. Пожалуйста, не сообщайте о связанных с ними проблемах!</string>
+ <string name="label_experimental_settings_word_confirm_title">Фраза подтверждения</string>
+ <string name="label_experimental_settings_word_confirm_summary">Подтвердить ключи с помощью фраз, вместо шестнадцатеричных отпечатков </string>
+ <string name="label_experimental_settings_linked_identities_title">Связанные идентификаторы</string>
+ <string name="label_experimental_settings_linked_identities_summary">Привязать ключи к Twitter, GitHub, веб-сайту или DNS (по аналогии с keybase.io но децентрализованно)</string>
+ <string name="label_experimental_settings_keybase_title">Keybase.io подтверждение</string>
+ <string name="label_experimental_settings_keybase_summary">Опрашивать keybase.io для подтверждения ключей и показывать это каждый раз при отображении ключей</string>
<!--Proxy Preferences-->
<string name="pref_proxy_tor_title">Использовать Tor</string>
<string name="pref_proxy_tor_summary">Требуется установка Orbot</string>
@@ -187,8 +213,6 @@
<string name="orbot_start_dialog_start">Запустить Orbot</string>
<string name="orbot_start_dialog_cancel">Отмена</string>
<string name="orbot_start_dialog_ignore_tor">Не использовать Tor</string>
- <string name="user_id_no_name">&lt;нет имени&gt;</string>
- <string name="none">&lt;нет&gt;</string>
<plurals name="n_keys">
<item quantity="one">1 ключ</item>
<item quantity="few">%d ключей</item>
@@ -216,6 +240,7 @@
<string name="choice_4hours">4 часа</string>
<string name="choice_8hours">8 часов</string>
<string name="choice_forever">всегда</string>
+ <string name="choice_select_cert">Выбрать ключ</string>
<string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string>
@@ -236,7 +261,7 @@
<string name="no_filemanager_installed">Нет совместимого менеджера файлов.</string>
<string name="passphrases_do_not_match">Пароли не совпадают.</string>
<string name="passphrase_must_not_be_empty">Пожалуйста, введите пароль.</string>
- <string name="passphrase_for_symmetric_encryption">Симметричное шифрование.</string>
+ <string name="passphrase_for_symmetric_encryption">Введите пароль</string>
<string name="passphrase_for">Введите пароль для \'%s\'</string>
<string name="pin_for">Введите PIN для
\'%s\'</string>
@@ -252,7 +277,6 @@
<string name="specify_file_to_encrypt_to">Пожалуйста, укажите, в какой файл произвести шифрование.\nВНИМАНИЕ: Файл будет перезаписан, если он уже существует!</string>
<string name="specify_file_to_decrypt_to">Пожалуйста, укажите, в какой файл произвести расшифровку.\nВНИМАНИЕ: Файл будет перезаписан, если он уже существует!</string>
<string name="key_deletion_confirmation_multi">Вы правда хотите удалить выбранные ключи?</string>
- <string name="secret_key_deletion_confirmation">После удаления будет невозможно прочесть сообщения зашифрованные данным ключом и утрачены все подтверждения ключей выполненные с его помощью!</string>
<string name="public_key_deletetion_confirmation">Удалить ключ \'%s\'?</string>
<string name="also_export_secret_keys">Экспортировать секретные ключи</string>
<string name="reinstall_openkeychain">Вы столкнулись с багом Андроид. Пожалуйста, переустановите OpenKeychain чтобы связать ваши контакты и ключи. </string>
@@ -261,13 +285,11 @@
<string name="no_keys_exported">Ключи не были экспортированы.</string>
<string name="key_creation_el_gamal_info">Прим.: только вторичные ключи поддерживают ElGamal.</string>
<string name="key_not_found">Не удается найти ключ %08X.</string>
- <string name="specify_file_to_export_log_to">Пожалуйста, выберите файл в который произвести экспорт.\nВНИМАНИЕ! Файл будет перезаписан если он уже существует!</string>
<string name="list_empty">Список пуст!</string>
<string name="nfc_successful">Ключ успешно передан через NFC!</string>
<string name="key_copied_to_clipboard">Ключ скопирован в буфер обмена!</string>
<string name="fingerprint_copied_to_clipboard">Отпечаток ключа скопирован в буфер обмена!</string>
<string name="select_key_to_certify">Выберите ключ, используемый для подтверждения!</string>
- <string name="key_too_big_for_sharing">Ключ слишком большой для этого способа передачи!</string>
<string name="text_copied_to_clipboard">Тест скопирован в буфер обмена!</string>
<!--errors
no punctuation, all lowercase,
@@ -351,8 +373,8 @@
<string name="progress_encrypting">шифрование данных...</string>
<string name="progress_decrypting">расшифровка данных...</string>
<string name="progress_preparing_signature">подготовка подписи...</string>
- <string name="progress_generating_signature">формирование подписи...</string>
<string name="progress_processing_signature">обработка подписи...</string>
+ <string name="progress_generating_signature">формирование подписи...</string>
<string name="progress_verifying_signature">проверка подписи...</string>
<string name="progress_signing">подписание...</string>
<string name="progress_certifying">сертификация...</string>
@@ -364,14 +386,9 @@
<string name="progress_deleting">удаление ключей...</string>
<string name="progress_con_saving">объединение: сохранение в кэш...</string>
<string name="progress_con_reimport">объединение: реимпорт...</string>
- <string name="progress_verifying_keyserver_url">подтверждение сервера ключей...</string>
<!--action strings-->
<string name="hint_cloud_search_hint">Искать через Имя, Email...</string>
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -401,7 +418,7 @@
<string name="help_about_version">Версия:</string>
<!--Import-->
<string name="import_tab_keyserver">Сервер ключей</string>
- <string name="import_tab_cloud">Поиск в облаке</string>
+ <string name="import_tab_cloud">Поиск ключа</string>
<string name="import_tab_direct">Файл/Буфер</string>
<string name="import_tab_qr_code">QR код/NFC</string>
<string name="import_import">Импорт выбранных ключей</string>
@@ -416,12 +433,6 @@
<string name="with_warnings">, с предупреждениями</string>
<string name="with_cancelled">, до отмены</string>
<!--Import result toast-->
- <plurals name="import_keys_added_and_updated_1">
- <item quantity="one">Ключ успешно импортирован</item>
- <item quantity="few">Успешно добавлено %1$d ключей</item>
- <item quantity="many">Успешно добавлено %1$d ключей</item>
- <item quantity="other">Успешно добавлено %1$d ключей</item>
- </plurals>
<string name="import_error_nothing">Нет данных для импорта.</string>
<string name="import_error_nothing_cancelled">Импорт отменен.</string>
<!--Delete result toast-->
@@ -481,7 +492,7 @@
</plurals>
<string name="key_list_empty_text1">Ключи не найдены!</string>
<string name="key_list_filter_show_all">Показать все ключи</string>
- <string name="key_list_filter_show_certified">Показать только сертифицированные ключи</string>
+ <string name="key_list_fab_search">Поиск ключа</string>
<!--Key view-->
<string name="key_view_action_edit">Изменить ключ</string>
<string name="key_view_action_encrypt">Зашифровать текст</string>
@@ -498,17 +509,9 @@
<string name="key_view_tab_keybase">Keybase.io</string>
<string name="user_id_info_revoked_title">Аннулировано</string>
<string name="user_id_info_revoked_text">Этот идентификатор отозван владельцем ключа. Он больше недействителен.</string>
- <string name="user_id_info_certified_title">Сертифицировано</string>
- <string name="user_id_info_certified_text">Этот идентификатор был сертифицирован Вами</string>
- <string name="user_id_info_uncertified_title">Не сертифицирован</string>
- <string name="user_id_info_uncertified_text">Этот идентификатор не был заверен. Нет гарантии, что он принадлежит этому человеку.</string>
<string name="user_id_info_invalid_title">Недействительно</string>
<string name="user_id_info_invalid_text">Что-то не так с идентификатором!</string>
<!--Key trust-->
- <string name="key_trust_already_verified">Этот ключ уже подтверждён!</string>
- <string name="key_trust_it_is_yours">Это один из ваших ключей!</string>
- <string name="key_trust_revoked">Этот ключ отозван владельцем. Вы не должны доверять ему.</string>
- <string name="key_trust_expired">У этого ключа истек срок годности. Вы не должны доверять ему.</string>
<string name="key_trust_start_cloud_search">Начать поиск</string>
<!--keybase proof stuff-->
<string name="keybase_proof_failure">К сожалению это доказательство не может быть верифицировано.</string>
@@ -543,7 +546,7 @@
<string name="edit_key_error_add_identity">Добавьте хотя бы один идентификатор!</string>
<string name="edit_key_error_add_subkey">Добавьте хотя бы один доп. ключ!</string>
<!--Create key-->
- <string name="create_key_upload">Синхронизировать с облаком</string>
+ <string name="create_key_upload">Синхронизация с Интернет</string>
<string name="create_key_empty">Это обязательне поле</string>
<string name="create_key_passphrases_not_equal">Пароли не совпадают</string>
<string name="create_key_final_text">Вы указали следующие данные:</string>
@@ -568,7 +571,6 @@
<string name="view_key_fragment_no_system_contact">&lt;нет&gt;</string>
<!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Добавить сервер ключей</string>
- <string name="add_keyserver_verified">Сервер ключей подтверждён!</string>
<string name="add_keyserver_without_verification">Сервер ключей добавлен без подтверждения.</string>
<string name="add_keyserver_invalid_url">Неправильный адрес!</string>
<!--Navigation Drawer-->
@@ -627,7 +629,6 @@
<string name="msg_ip_master_flags_xxxa">Основные флаги: удостоверить</string>
<string name="msg_ip_master_flags_xxxx">Основные флаги: нет</string>
<string name="msg_ip_merge_public">Объединение импортированных данных с существующей связкой публичных ключей</string>
- <string name="msg_ip_merge_secret">Объединение импортированных данных с существующей связкой публичных ключей</string>
<string name="msg_ip_subkey">Обработка доп. ключа %s</string>
<string name="msg_ip_subkey_expired">Срок годности доп. ключа истек %s</string>
<string name="msg_ip_subkey_expires">Срок годности доп. ключа истекает %s</string>
@@ -681,7 +682,6 @@
<string name="msg_is_importing_subkeys">Обработка секретных доп. ключей</string>
<string name="msg_is_error_io_exc">Ошибка кодирования ключа</string>
<string name="msg_is_merge_public">Объединение импортированных данных с существующей связкой публичных ключей</string>
- <string name="msg_is_merge_secret">Объединение импортированных данных с существующей связкой публичных ключей</string>
<string name="msg_is_merge_special">Объединение само-сертифицированных данных из публичных ключей</string>
<string name="msg_is_pubring_generate">Формирование публичной связки из секретной связки</string>
<string name="msg_is_subkey_nonexistent">Доп. ключ %s недоступен в секретном ключе</string>
@@ -768,7 +768,6 @@
<string name="msg_cr_error_no_user_id">Связки должны создаваться с хотя бы одним ID пользователя!</string>
<string name="msg_cr_error_no_certify">Основной ключ должен иметь флаг сертификата!</string>
<string name="msg_cr_error_null_expiry">Срок годности не может быть \'такой же как раньше\' при создании ключа. Это программная ошибка, пожалуйста, сообщите об этом!</string>
- <string name="msg_cr_error_keysize_512">Размер ключа должен быть больше или равен 512!</string>
<string name="msg_cr_error_no_curve">Не задан размер ключа! Это программная ошибка, пожалуйста, сообщите об этом!</string>
<string name="msg_cr_error_no_keysize">Не задана эллиптическая кривая! Это программная ошибка, пожалуйста, сообщите об этом!</string>
<string name="msg_cr_error_internal_pgp">Внутренняя ошибка OpenPGP!</string>
@@ -855,7 +854,6 @@
<string name="msg_se_success">Операция подписи/шифрования успешна!</string>
<!--Messages for PgpSignEncrypt operation-->
<string name="msg_pse_asymmetric">Подготовка публичных ключей для шифрования</string>
- <string name="msg_pse_clearsign_only">Подписание пустого текста не поддерживается!</string>
<string name="msg_pse_compressing">Подготовка сжатия</string>
<string name="msg_pse_encrypting">Шифрование данных</string>
<string name="msg_pse_error_bad_passphrase">Неверный пароль!</string>
@@ -879,20 +877,12 @@
<string name="msg_crt_warn_cert_failed">Создание сертификата не удалось!</string>
<string name="msg_crt_warn_save_failed">Ошибка операции сохранения!</string>
<string name="msg_crt_upload_success">Ключ успешно загружен на сервер</string>
- <string name="msg_import_fingerprint_ok">Проверка отпечатка успешна</string>
<string name="msg_import_error">Ошибка операции импорта!</string>
<string name="msg_import_error_io">Операция импорта прервана из-за ошибки ввода/вывода!</string>
<string name="msg_import_success">Операция импорта успешна!</string>
- <string name="msg_export_all">Экспорт всех ключей</string>
- <string name="msg_export_error_no_file">Не выбрано имя файла!</string>
- <string name="msg_export_error_fopen">Ошибка открытия файла!</string>
- <string name="msg_export_error_no_uri">Не выбран URL!</string>
- <string name="msg_export_error_storage">Диск не готов для записи!</string>
- <string name="msg_export_error_db">Ошибка базы данных!</string>
- <string name="msg_export_error_io">Ошибка ввода/вывода!</string>
- <string name="msg_export_success">Операция экспорта успешна</string>
<string name="msg_del_error_empty">Нет данных для удаления!</string>
<string name="msg_del_error_multi_secret">Секретные ключи можно удалять только по одному!</string>
+ <!--Linked Identity verification-->
<string name="msg_acc_saved">Аккаунт сохранен</string>
<string name="msg_download_success">Загрузка завершена!</string>
<plurals name="error_import_non_pgp_part">
@@ -902,12 +892,7 @@
<item quantity="other">части загруженного файла содержат данные OpenPGP, но это не ключ</item>
</plurals>
<!--Messages for Keybase Verification operation-->
- <!--Messages for Export Log operation-->
- <string name="msg_export_log_start">Экспорт журнала...</string>
- <string name="msg_export_log_error_fopen">Ошибка открытия файла</string>
- <string name="msg_export_log_error_no_file">Не выбрано имя файла!</string>
- <string name="msg_export_log_error_writing">Ошибка записи в файл!</string>
- <string name="msg_export_log_success">Лог успешно экспортирован!</string>
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<string name="passp_cache_notif_pwd">Пароль</string>
<!--Keyserver sync-->
@@ -921,7 +906,6 @@
<string name="section_certifier_id">Кем подписан</string>
<string name="section_cert">Детали сертификации</string>
<string name="label_user_id">Идентификатор</string>
- <string name="unknown_uid">&lt;неизв.&gt;</string>
<string name="empty_certs">Этот ключ не сертифицирован</string>
<string name="label_revocation">Причина отзыва</string>
<string name="label_cert_type">Тип</string>
@@ -962,4 +946,13 @@
<string name="snack_yubikey_import">Импорт</string>
<string name="yubikey_key_holder">Владелец ключа:</string>
<string name="error_nfc">Ошибка NFC: %s</string>
+ <!--Other Linked Identity strings-->
+ <string name="linked_select_2">Пожалуйста, выберите тип:</string>
+ <string name="section_linked_identities">Связанные идентификаторы</string>
+ <string name="btn_finish">Завершить</string>
+ <string name="linked_title_twitter">Твиттер</string>
+ <string name="linked_button_retry">Повторить</string>
+ <string name="linked_button_confirm">Подтвердить</string>
+ <string name="linked_text_error">Ошибка</string>
+ <string name="share_log_dialog_share_button">Опубликовать</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-sl/strings.xml b/OpenKeychain/src/main/res/values-sl/strings.xml
index 32f63b9b4..cceff9221 100644
--- a/OpenKeychain/src/main/res/values-sl/strings.xml
+++ b/OpenKeychain/src/main/res/values-sl/strings.xml
@@ -26,16 +26,13 @@
<string name="title_log_display">Dnevnik</string>
<string name="title_exchange_keys">Izmenjava ključev</string>
<string name="title_delete_secret_key">Izbrišem VAŠ ključ \'%s\'?</string>
- <string name="title_export_log">Izvozi sistemsko zabeležbo</string>
<string name="title_manage_my_keys">Upravljanje mojih ključev</string>
<!--section-->
<string name="section_user_ids">Identitete</string>
<string name="section_linked_system_contact">Povezan stik</string>
<string name="section_should_you_trust">Ali zaupate temu ključu?</string>
<string name="section_proof_details">Overba dokazila</string>
- <string name="section_cloud_evidence">Dokazila iz oblaka</string>
<string name="section_keys">Podključi</string>
- <string name="section_cloud_search">Iskanje v oblaku</string>
<string name="section_certify">Potrdi</string>
<string name="section_actions">Ravnanja</string>
<string name="section_share_key">Ključ</string>
@@ -57,8 +54,6 @@
<string name="btn_back">Nazaj</string>
<string name="btn_no">Ne</string>
<string name="btn_match">Prstna odtisa se ujemata</string>
- <string name="btn_share_encrypted_signed">Šifriraj in deli besedilo</string>
- <string name="btn_copy_encrypted_signed">Šifriraj besedilo in kopiraj v odložišče</string>
<string name="btn_view_cert_key">Poglej ključ za overjanje</string>
<string name="btn_create_key">Ustvari ključ</string>
<string name="btn_add_files">Dodaj datoteko</string>
@@ -77,8 +72,6 @@
<string name="menu_select_all">Izberi vse</string>
<string name="menu_export_all_keys">Izvozi vse ključe</string>
<string name="menu_update_all_keys">Posodobi vse ključe</string>
- <string name="menu_certify_fingerprint">Potrdi s primerjavo prstnih odtisov</string>
- <string name="menu_export_log">Izvozi sistemsko zabeležbo</string>
<!--label-->
<string name="label_message">Besedilo</string>
<string name="label_file">Datoteka</string>
@@ -90,9 +83,7 @@
<string name="label_file_ascii_armor">Omogoči ASCII ovoj</string>
<string name="label_write_version_header">Daj drugim vedeti, da uporabljate OpenKeychain</string>
<string name="label_write_version_header_summary">Zapiše \'OpenKeychain v2.7\' v OpenPGP podpis, šifrirano besedilo in izvožene ključe</string>
- <string name="label_use_default_yubikey_pin">Uporabi privzeto YubiKey PIN kodo</string>
<string name="label_use_num_keypad_for_yubikey_pin">Uporabi numerično tipkovnico za YubiKey PIN kodo</string>
- <string name="label_label_use_default_yubikey_pin_summary">Uporablja privzeto PIN kodo (123456) za dostop do ključev YubiKey preko NFC</string>
<string name="label_to">Šifriraj za:</string>
<string name="label_delete_after_encryption">Po dešifriranju izbriši datoteke</string>
<string name="label_delete_after_decryption">Izbriši po dešifriranju</string>
@@ -110,7 +101,6 @@
<string name="label_name">Ime</string>
<string name="label_comment">Komentar</string>
<string name="label_email">E-pošta</string>
- <string name="label_send_key">Sinhroniziraj z oblakom</string>
<string name="label_fingerprint">Prstni odtis</string>
<string name="expiry_date_dialog_title">Določi datum poteka veljavnosti</string>
<string name="label_preferred">prednostni</string>
@@ -123,8 +113,6 @@
<!--OrbotHelper strings-->
<!--InstallDialogFragment strings-->
<!--StartOrbotDialogFragment strings-->
- <string name="user_id_no_name">&lt;brez imena&gt;</string>
- <string name="none">&lt;nič&gt;</string>
<plurals name="n_keys">
<item quantity="one">1 ključ</item>
<item quantity="two">%d ključa</item>
@@ -167,7 +155,6 @@
<string name="flag_authenticate">Preveri avtentičnost</string>
<!--sentences-->
<string name="no_filemanager_installed">Nimate nameščenega združljivega upravljalnika datotek.</string>
- <string name="passphrase_for_symmetric_encryption">Simetrično šifriranje.</string>
<string name="pin_for">Vnesite PIN kodo za \'%s\'</string>
<string name="yubikey_pin_for">Vnesite PIN kodo za dostop YubiKey za \'%s\'</string>
<string name="file_delete_confirmation_title">Izbrišem izvirne datoteke?</string>
@@ -179,7 +166,6 @@
<string name="specify_file_to_encrypt_to">Določite datoteko, v katero želite šifrirati vsebino.\nPOZOR: če datoteka že obstaja, bo prepisana.</string>
<string name="specify_file_to_decrypt_to">Določite datoteko, v katero želite dešifrirati vsebino.\nPOZOR: če datoteka že obstaja, bo prepisana.</string>
<string name="key_deletion_confirmation_multi">Ali zares želite izbrisati vse izbrane ključe?</string>
- <string name="secret_key_deletion_confirmation">Po izbrisu ne bo več mogoče prebirati sporočil šifriranih s tem ključem! Izgubljene bodo tudi vse z njim narejene potrditve.</string>
<string name="public_key_deletetion_confirmation">Izbrišem ključ \'%s\'?</string>
<string name="also_export_secret_keys">Izvozi tudi zasebne ključe</string>
<string name="reinstall_openkeychain">Naleteli ste na poznanega \'hrošča\' v sistemu Android. Za povezavo vaših stikov s ključi ponovno naložite aplikacijo OpenKeycahain.</string>
@@ -188,7 +174,6 @@
<string name="no_keys_exported">Noben ključ ni bil izvožen.</string>
<string name="key_creation_el_gamal_info">Pozor: ELGamal podpirajo samo podključi.</string>
<string name="key_not_found">Ne najdem ključa %08X.</string>
- <string name="specify_file_to_export_log_to">Določite datoteko, v katero želite izvoziti vsebino.\nPOZOR: če datoteka že obstaja, bo prepisana.</string>
<plurals name="bad_keys_encountered">
<item quantity="one">Neupoštevan %d slab zasebni ključ. Morda je bil izvožen na način\n --export-secret-subkeys\nPoskrbite, da bo izvožen z\n --export-secret-keys</item>
<item quantity="two">Neupoštevana %d slaba zasebna ključa. Morda sta bila izvožena na način\n --export-secret-subkeys\nPoskrbite, da bosta izvožena z\n --export-secret-keys</item>
@@ -200,7 +185,6 @@
<string name="key_copied_to_clipboard">Ključ je bil prekopiran v odložišče!</string>
<string name="fingerprint_copied_to_clipboard">Prstni odtis je bil prekopiran v odložišče!</string>
<string name="select_key_to_certify">Izberite ključ, ki ga boste uporabljali za potrjevanje!</string>
- <string name="key_too_big_for_sharing">Ključ je prevelik za delitev na ta način!</string>
<string name="text_copied_to_clipboard">Besedilo je bilo prekopirano v odložišče!</string>
<!--errors
no punctuation, all lowercase,
@@ -272,8 +256,8 @@
<string name="progress_encrypting">šifriram podatke...</string>
<string name="progress_decrypting">dešifriram podatke...</string>
<string name="progress_preparing_signature">pripravljam podpis...</string>
- <string name="progress_generating_signature">ustvarjam podpis...</string>
<string name="progress_processing_signature">obdelujem podpis...</string>
+ <string name="progress_generating_signature">ustvarjam podpis...</string>
<string name="progress_verifying_signature">preverjam podpis...</string>
<string name="progress_signing">podpisujem...</string>
<string name="progress_certifying">overjanje...</string>
@@ -288,10 +272,6 @@
<!--action strings-->
<string name="hint_cloud_search_hint">Iskanje po Imenu, E-pošti...</string>
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -321,7 +301,6 @@
<string name="help_about_version">Različica:</string>
<!--Import-->
<string name="import_tab_keyserver">Strežnik</string>
- <string name="import_tab_cloud">Iskanje v oblaku</string>
<string name="import_tab_direct">Datoteka/odložišče</string>
<string name="import_tab_qr_code">Koda QR/NFC</string>
<string name="import_import">Uvozi izbrane ključe</string>
@@ -333,18 +312,6 @@
<string name="with_warnings">, z opozorili</string>
<string name="with_cancelled">, do preklica</string>
<!--Import result toast-->
- <plurals name="import_keys_added_and_updated_1">
- <item quantity="one">Uspešno uvožen ključ</item>
- <item quantity="two">Uspešno uvožena %1$d ključa</item>
- <item quantity="few">Uspešno uvoženi %1$d ključi</item>
- <item quantity="other">Uspešno uvoženih %1$d ključev</item>
- </plurals>
- <plurals name="import_keys_added_and_updated_2">
- <item quantity="one">in posodobljen ključ%2$s.</item>
- <item quantity="two">in posodobljena %1$d ključa%2$s.</item>
- <item quantity="few">in posodobljeni %1$d ključi%2$s.</item>
- <item quantity="other">in posodobljenih %1$d ključev%2$s.</item>
- </plurals>
<plurals name="import_keys_added">
<item quantity="one">Uspešno uvožen ključ%2$s.</item>
<item quantity="two">Uspešno uvožena %1$d ključa%2$s.</item>
@@ -400,12 +367,6 @@
<string name="delete_cancelled">Operacija brisanja prekinjena.</string>
<!--Revoke result toast (snackbar)-->
<!--Certify result toast-->
- <plurals name="certify_keys_ok">
- <item quantity="one">Uspešno potrjen ključ%2$s.</item>
- <item quantity="two">Uspešno potrjena %1$d ključa%2$s.</item>
- <item quantity="few">Uspešno potrjeni %1$d ključi%2$s.</item>
- <item quantity="other">Uspešno potrjenih %1$d ključev%2$s.</item>
- </plurals>
<plurals name="certify_keys_with_errors">
<item quantity="one">Ključ ni bil potrjen!</item>
<item quantity="two">%d ključa nista bila potrjena!</item>
@@ -463,7 +424,6 @@
</plurals>
<string name="key_list_empty_text1">Najden ni bil noben ključ!</string>
<string name="key_list_filter_show_all">Prikaži vse ključe</string>
- <string name="key_list_filter_show_certified">Prikaži samo overjene ključe</string>
<!--Key view-->
<string name="key_view_action_edit">Uredi ključ</string>
<string name="key_view_action_encrypt">Šifriraj besedilo</string>
@@ -480,23 +440,11 @@
<string name="key_view_tab_keybase">Keybase.io</string>
<string name="user_id_info_revoked_title">Preklican</string>
<string name="user_id_info_revoked_text">Lastnik ključa je preklical to identiteto. Ta ni več veljavna.</string>
- <string name="user_id_info_certified_title">Overjeno</string>
- <string name="user_id_info_certified_text">Ta identiteta je bila overjena z vaše strani.</string>
- <string name="user_id_info_uncertified_title">Neoverjeno</string>
- <string name="user_id_info_uncertified_text">Ta identiteta še ni bila overjena, zato ni mogoče vedeti, če ustreza osebi za katero se predstavlja.</string>
<string name="user_id_info_invalid_title">Neveljaven</string>
<string name="user_id_info_invalid_text">Nekaj je narobe s to identiteto!</string>
<!--Key trust-->
- <string name="key_trust_already_verified">Ta ključ ste že potrdili!</string>
- <string name="key_trust_it_is_yours">To je en izmed vaših ključev!</string>
- <string name="key_trust_maybe">Ta ključ ni niti preklican, niti potečen.\nNiste ga potrdili, a mogoče mu zaupate.</string>
- <string name="key_trust_revoked">Ta ključ je bil preklican s strani lastnika, zato mu ne gre zaupati.</string>
- <string name="key_trust_expired">Ta ključ je potekel, zato mu ne gre zaupati.</string>
- <string name="key_trust_old_keys">Uporaba tega ključa za dešifriranje starejših sporočil iz časa, ko ključ še ni potekel, oz. bil preklican, ni kritična.</string>
- <string name="key_trust_no_cloud_evidence">Ni podatkov z oblaka o pristnosti tega ključa.</string>
<string name="key_trust_start_cloud_search">Začni iskanje</string>
<string name="key_trust_results_prefix">Keybase.io ponuja \"dokazilo\", da je lastnik tega kluča:</string>
- <string name="key_trust_header_text">Pozor: Dokazila Keybase.io v aplikaciji OpenKeychain so eksperimantalne narave. Za večjo zanesljivost priporočamo, da dodatno skenirate kode QR ali izmenjate ključe preko NFC.</string>
<!--keybase proof stuff-->
<string name="keybase_proof_failure">Dokazila se žal ne da preveriti.</string>
<string name="keybase_unknown_proof_failure">Neznan problem pri pregledovalniku dokazil</string>
@@ -532,7 +480,6 @@
<string name="edit_key_error_add_identity">Dodajte vsaj eno identiteto!</string>
<string name="edit_key_error_add_subkey">Dodajte vsaj en podključ!</string>
<!--Create key-->
- <string name="create_key_upload">Sinhroniziraj z oblakom</string>
<string name="create_key_empty">To polje je obvezno</string>
<string name="create_key_final_text">Vnesli ste identiteto:</string>
<string name="create_key_final_robot_text">Ustvarjanje ključa zna potrajati. Privoščite si kavo...</string>
@@ -609,7 +556,6 @@
<string name="msg_ip_master_flags_xxxa">Glavne oznake: overi</string>
<string name="msg_ip_master_flags_xxxx">Glavne oznake: brez</string>
<string name="msg_ip_merge_public">Združujem uvožene podatke z obstoječo zbirko javnih ključev</string>
- <string name="msg_ip_merge_secret">Združujem uvožene podatke z obstoječo zbirko javnih ključev</string>
<string name="msg_ip_subkey">Obdelujem podključ %s</string>
<string name="msg_ip_subkey_expired">Podključ je potekel %s</string>
<string name="msg_ip_subkey_expires">Podključ poteče %s</string>
@@ -676,7 +622,6 @@
<string name="msg_is_importing_subkeys">Procesiram zasebne podključe</string>
<string name="msg_is_error_io_exc">Napaka pri kodiranju zbirke ključev</string>
<string name="msg_is_merge_public">Združujem uvožene podatke v obstoječo zbirko ključev</string>
- <string name="msg_is_merge_secret">Združujem uvožene podatke v obstoječo javno zbirko ključev</string>
<string name="msg_is_merge_special">Združujem podatke o samo-potrdilih iz javne zbirke ključev</string>
<string name="msg_is_pubring_generate">Generiram javno zbirko ključev iz zasebne</string>
<string name="msg_is_subkey_nonexistent">Podključ %s ni na voljo v zasebnem ključu</string>
@@ -799,6 +744,7 @@
<string name="msg_crt_error_self">Tak način izdajanja samo-potrdil ni mogoč!</string>
<string name="msg_crt_warn_not_found">Ključ ni bil najden!</string>
<string name="msg_crt_warn_cert_failed">Generacija potrdila ni uspela!</string>
+ <!--Linked Identity verification-->
<plurals name="error_import_non_pgp_part">
<item quantity="one">Del naložene datoteke je veljavnen objekt OpenPGP a ni ključ.</item>
<item quantity="two">Deli naložene datoteke so veljavni objekti OpenPGP a niso ključi.</item>
@@ -806,7 +752,7 @@
<item quantity="other">Deli naložene datoteke so veljavni objekti OpenPGP a niso ključi.</item>
</plurals>
<!--Messages for Keybase Verification operation-->
- <!--Messages for Export Log operation-->
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<!--Keyserver sync-->
<!--First Time-->
@@ -816,7 +762,6 @@
<string name="section_certifier_id">Overovitelj</string>
<string name="section_cert">Podrobnosti potrdil</string>
<string name="label_user_id">Identiteta</string>
- <string name="unknown_uid">&lt;neznan&gt;</string>
<string name="empty_certs">Ni potrdil za ta ključ</string>
<string name="certs_text">Tu so prikazana samo preverjena samo-potrdila in preverjena potrdila ustvarjena z vašimi ključi</string>
<string name="label_revocation">Razlog za preklic</string>
@@ -836,4 +781,5 @@
<!--TODO: rename all the things!-->
<!--<string name="enter_passphrase_twice">Enter password twice</string>-->
<!--<string name="nfc_text">Please place a NFC tag near your device</string>-->
+ <!--Other Linked Identity strings-->
</resources>
diff --git a/OpenKeychain/src/main/res/values-sr/strings.xml b/OpenKeychain/src/main/res/values-sr/strings.xml
index 5c6d03950..7b9ef3238 100644
--- a/OpenKeychain/src/main/res/values-sr/strings.xml
+++ b/OpenKeychain/src/main/res/values-sr/strings.xml
@@ -31,7 +31,6 @@
<string name="title_exchange_keys">Размена кључева</string>
<string name="title_advanced_key_info">Додатни подаци</string>
<string name="title_delete_secret_key">Обрисати ВАШ кључ „%s“?</string>
- <string name="title_export_log">Извоз дневника</string>
<string name="title_manage_my_keys">Управљање мојим кључевима</string>
<!--section-->
<string name="section_user_ids">Идентитети</string>
@@ -39,13 +38,14 @@
<string name="section_linked_system_contact">Повезани контакт</string>
<string name="section_should_you_trust">Смијете ли да се поуздате у овај кључ?</string>
<string name="section_proof_details">Овера доказа</string>
- <string name="section_cloud_evidence">Докази са клауда</string>
<string name="section_keys">Поткључеви</string>
- <string name="section_cloud_search">Претрага клауда</string>
- <string name="section_passphrase_cache">Руковање лозинком/ПИНом</string>
- <string name="section_proxy_settings">Поставке проксија</string>
+ <string name="section_cloud_search_summary">Сервер кључева, keybase.io</string>
+ <string name="section_passphrase_cache">Лозинке и пинови</string>
+ <string name="section_proxy_settings_summary">Тор, поставке проксија</string>
<string name="section_gui">Сучеље</string>
- <string name="section_sync_settings">Поставке синхронизације</string>
+ <string name="section_sync_settings">Синхронизација</string>
+ <string name="section_sync_settings_summary">Аутоматско ажурирање кључева, повезивање контаката</string>
+ <string name="section_experimental_features">Експерименталне функције</string>
<string name="section_certify">Потврда</string>
<string name="section_actions">Радње</string>
<string name="section_share_key">Кључ</string>
@@ -71,12 +71,9 @@
<string name="btn_back">Назад</string>
<string name="btn_no">Не</string>
<string name="btn_match">Отисци се поклапају</string>
- <string name="btn_share_encrypted_signed">Шифруј и подели текст</string>
- <string name="btn_copy_encrypted_signed">Шифруј и копирај текст</string>
<string name="btn_view_cert_key">Прикажи кључ за оверавање</string>
<string name="btn_create_key">Направи кључ</string>
<string name="btn_add_files">Додај фајл(ове)</string>
- <string name="btn_share_decrypted_text">Подели дешифровани текст</string>
<string name="btn_copy_decrypted_text">Копирај дешифровани текст</string>
<string name="btn_decrypt_clipboard">Учитај са клипборда</string>
<string name="btn_decrypt_files">Изабери фајл</string>
@@ -90,7 +87,6 @@
<!--menu-->
<string name="menu_preferences">Поставке</string>
<string name="menu_help">Помоћ</string>
- <string name="menu_export_key">Направи резерву у фајл</string>
<string name="menu_delete_key">Обриши кључ</string>
<string name="menu_manage_keys">Управљај мојим кључевима</string>
<string name="menu_search">Претрага</string>
@@ -101,8 +97,7 @@
<string name="menu_export_all_keys">Извези све кључеве</string>
<string name="menu_update_all_keys">Ажурирај све кључеве</string>
<string name="menu_advanced">Додатни подаци</string>
- <string name="menu_certify_fingerprint">Потврди поређењем отисака</string>
- <string name="menu_export_log">Извези дневник</string>
+ <string name="menu_certify_fingerprint">Потврди помоћу отиска</string>
<string name="menu_keyserver_add">Додај</string>
<!--label-->
<string name="label_message">Текст</string>
@@ -119,9 +114,7 @@
<string name="label_file_ascii_armor">Омогући Аски оклоп</string>
<string name="label_write_version_header">Упиши да користим Отворени кључарник</string>
<string name="label_write_version_header_summary">Уписује „OpenKeychain v3.0“ у ОпенПГП потписе, шифровани текст и извезене кључеве</string>
- <string name="label_use_default_yubikey_pin">Користи подразумевани Јубикључ ПИН</string>
<string name="label_use_num_keypad_for_yubikey_pin">Користи бројчану тастатуру за Јубикључ ПИН</string>
- <string name="label_label_use_default_yubikey_pin_summary">Користи подразумевани ПИН (123456) за приступ Јубикључевима преко НФЦ-а</string>
<string name="label_asymmetric_from">Потпиши помоћу:</string>
<string name="label_to">Шифруј за:</string>
<string name="label_delete_after_encryption">Обриши фајлове након шифровања</string>
@@ -145,7 +138,6 @@
<string name="label_name">Име</string>
<string name="label_comment">Коментар</string>
<string name="label_email">Е-адреса</string>
- <string name="label_send_key">Синхронизуј са клаудом</string>
<string name="label_fingerprint">Отисак</string>
<string name="expiry_date_dialog_title">Датум истицања</string>
<string name="label_keyservers_title">Сервери кључева</string>
@@ -155,8 +147,6 @@
<string name="label_enable_compression">Омогући компресију</string>
<string name="label_encrypt_filenames">Шифруј имена фајлова</string>
<string name="label_hidden_recipients">Сакриј примаоце</string>
- <string name="label_verify_keyserver">Овери сервер кључева</string>
- <string name="label_enter_keyserver_url">Унесите УРЛ сервера кључева</string>
<string name="label_keyserver_dialog_delete">Обриши сервер кључева</string>
<string name="label_theme">Тема</string>
<string name="pref_keyserver">ОпенПГП сервера кључева</string>
@@ -166,11 +156,10 @@
<string name="label_sync_settings_keyserver_title">Аутоматски ажурирај кључеве</string>
<string name="label_sync_settings_keyserver_summary_on">Кључеви старији од седам дана се ажурирају са пожељног сервера кључева</string>
<string name="label_sync_settings_keyserver_summary_off">Кључеви се не ажурирају аутоматски</string>
- <string name="label_sync_settings_contacts_title">Синхронизуј контакте са кључевима</string>
- <string name="label_sync_settings_contacts_summary_on">Кључеви повезани са контактима са поклапајућим е-адресама, одвија се у потпуности ван везе</string>
<string name="label_sync_settings_contacts_summary_off">Нови кључеви неће бити повезани са контактима</string>
<!--label shown in Android settings under the OpenKeychain account-->
<string name="keyserver_sync_settings_title">Аутоматски ажурирај кључеве</string>
+ <string name="label_experimental_settings_linked_identities_title">Повезани идентитети</string>
<!--Proxy Preferences-->
<string name="pref_proxy_tor_title">Омогући Тор</string>
<string name="pref_proxy_tor_summary">Захтева Орбот</string>
@@ -184,22 +173,18 @@
<string name="pref_proxy_type_choice_http">ХТТП</string>
<string name="pref_proxy_type_choice_socks">СОЦКС</string>
<!--OrbotHelper strings-->
- <string name="orbot_ignore_tor">Не користи Тор</string>
<!--InstallDialogFragment strings-->
<string name="orbot_install_dialog_title">Инсталирати Орбот да бих користио Тор?</string>
<string name="orbot_install_dialog_install">Инсталирај</string>
<string name="orbot_install_dialog_content">Морате имати Орбот инсталиран и активиран да бисте преусмерили саобраћај кроз њега. Желите ли да га инсталирате?</string>
<string name="orbot_install_dialog_cancel">Одустани</string>
- <string name="orbot_install_dialog_ignore_tor">Не користи Тор</string>
<!--StartOrbotDialogFragment strings-->
<string name="orbot_start_dialog_title">Да покренем Орбот?</string>
- <string name="orbot_start_dialog_content">Чини се да Орбот није покренут. Желите ли да га покренете и повежете са Тором?</string>
<string name="orbot_start_btn">Покрени Орбот</string>
<string name="orbot_start_dialog_start">Покрени Орбот</string>
<string name="orbot_start_dialog_cancel">Одустани</string>
- <string name="orbot_start_dialog_ignore_tor">Не користи Тор</string>
- <string name="user_id_no_name">&lt;нема имена&gt;</string>
- <string name="none">&lt;нема&gt;</string>
+ <string name="user_id_no_name"><![CDATA[<нема имена>]]></string>
+ <string name="none"><![CDATA[<ништа>]]></string>
<plurals name="n_keys">
<item quantity="one">%d кључ</item>
<item quantity="few">%d кључа</item>
@@ -225,6 +210,7 @@
<string name="choice_4hours">4 сата</string>
<string name="choice_8hours">8 сати</string>
<string name="choice_forever">заувек</string>
+ <string name="choice_select_cert">Изаберите кључ</string>
<string name="dsa">ДСА</string>
<string name="elgamal">Елгамал</string>
<string name="rsa">РСА</string>
@@ -245,7 +231,6 @@
<string name="no_filemanager_installed">Нема подесног менаџера фајлова.</string>
<string name="passphrases_do_not_match">Лозинке се не поклапају.</string>
<string name="passphrase_must_not_be_empty">Унесите лозинку.</string>
- <string name="passphrase_for_symmetric_encryption">Симетрично шифровање.</string>
<string name="passphrase_for">Унесите лозинку за „%s“</string>
<string name="pin_for">Унесите ПИН за „%s“</string>
<string name="yubikey_pin_for">Унесите ПИН за приступ Јубикључу за „%s“</string>
@@ -268,7 +253,6 @@
<string name="specify_backup_dest_secret_single">Биће направљена потпуна резерва вашег кључа, наведите одредишни фајл.\nУПОЗОРЕЊЕ: Фајл ће бити пребрисан ако већ постоји!</string>
<string name="specify_backup_dest_secret">Биће направљена потпуна резерва свих кључева укључујући и ваше, наведите одредишни фајл.\nУПОЗОРЕЊЕ: Фајл ће бити пребрисан ако већ постоји!</string>
<string name="key_deletion_confirmation_multi">Желите ли заиста да обришете све изабране кључеве?</string>
- <string name="secret_key_deletion_confirmation">Након брисања нећете моћи да читате поруке шифроване овим кључем и изгубићете све потврде кључева направљене њиме!</string>
<string name="public_key_deletetion_confirmation">Да обришем кључ „%s“?</string>
<string name="also_export_secret_keys">Такође извези тајне кључеве</string>
<string name="reinstall_openkeychain">Наишли сте на познату грешку у Андроиду. Поново инсталирајте Отворени кључарник ако желите да повежете ваше контакте са кључевима.</string>
@@ -277,7 +261,6 @@
<string name="no_keys_exported">Ниједан кључ није извезен.</string>
<string name="key_creation_el_gamal_info">Напомена: само поткључеви подржавају Елгамал.</string>
<string name="key_not_found">Нисам могао да нађем кључ %08X.</string>
- <string name="specify_file_to_export_log_to">Наведите у који фајл да извезем.\nУПОЗОРЕЊЕ: Фајл ће бити пребрисан ако постоји.</string>
<plurals name="bad_keys_encountered">
<item quantity="one">%d лош тајни кључ игнорисан. Можда сте извезли са аргументом\n --export-secret-subkeys\nУместо тога извезите са\n --export-secret-keys\"</item>
<item quantity="few">%d лоша тајна кључа игнорисана. Можда сте извезли са аргументом\n --export-secret-subkeys\nУместо тога извезите са\n --export-secret-keys\"</item>
@@ -288,7 +271,6 @@
<string name="key_copied_to_clipboard">Кључ је копиран на клипборд!</string>
<string name="fingerprint_copied_to_clipboard">Отисак је копиран на клипборд!</string>
<string name="select_key_to_certify">Изаберите кључ којим ћете извршити потврду!</string>
- <string name="key_too_big_for_sharing">Кључ је превелик да би се делио на овај начин!</string>
<string name="text_copied_to_clipboard">Текст је копиран на клипборд!</string>
<!--errors
no punctuation, all lowercase,
@@ -377,8 +359,8 @@
<string name="progress_encrypting">шифрујем податке…</string>
<string name="progress_decrypting">дешифрујем податке…</string>
<string name="progress_preparing_signature">припремам потпис…</string>
- <string name="progress_generating_signature">генеришем потпис…</string>
<string name="progress_processing_signature">обрађујем потпис…</string>
+ <string name="progress_generating_signature">генеришем потпис…</string>
<string name="progress_verifying_signature">оверавам потпис…</string>
<string name="progress_signing">потписујем…</string>
<string name="progress_certifying">оверавам…</string>
@@ -390,15 +372,10 @@
<string name="progress_deleting">бришем кључеве…</string>
<string name="progress_con_saving">учвршћивање: уписујем у кеш…</string>
<string name="progress_con_reimport">учвршћивање: поново увозим…</string>
- <string name="progress_verifying_keyserver_url">оверавам сервер кључева…</string>
<string name="progress_starting_orbot">Покрећем Орбот…</string>
<!--action strings-->
<string name="hint_cloud_search_hint">Тражи преко имена, е-адресе…</string>
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -428,7 +405,6 @@
<string name="help_about_version">Издање:</string>
<!--Import-->
<string name="import_tab_keyserver">Сервер кључева</string>
- <string name="import_tab_cloud">Клауд претрага</string>
<string name="import_tab_direct">Фајл/клипборд</string>
<string name="import_tab_qr_code">Бар-кôд/НФЦ</string>
<string name="import_import">Увези изабране кључеве</string>
@@ -444,16 +420,6 @@
<string name="with_warnings">, са упозорењима</string>
<string name="with_cancelled">, док није отказано</string>
<!--Import result toast-->
- <plurals name="import_keys_added_and_updated_1">
- <item quantity="one">Успешно увезен %1$d кључ</item>
- <item quantity="few">Успешно увезена %1$d кључа</item>
- <item quantity="other">Успешно увезено %1$d кључева</item>
- </plurals>
- <plurals name="import_keys_added_and_updated_2">
- <item quantity="one">и ажуриран %1$d кључ%2$s.</item>
- <item quantity="few">и ажурирана %1$d кључа%2$s.</item>
- <item quantity="other">и ажурирано %1$d кључева%2$s.</item>
- </plurals>
<plurals name="import_keys_added">
<item quantity="one">Успешно увезен %1$d кључ%2$s.</item>
<item quantity="few">Успешно увезена %1$d кључа%2$s.</item>
@@ -505,11 +471,6 @@
<string name="revoke_nothing">Нема ништа за опозив.</string>
<string name="revoke_cancelled">Радња опозива је отказана.</string>
<!--Certify result toast-->
- <plurals name="certify_keys_ok">
- <item quantity="one">Успешно оверен кључ%2$s.</item>
- <item quantity="few">Успешно оверена %1$d кључа%2$s.</item>
- <item quantity="other">Успешно оверено %1$d кључева%2$s.</item>
- </plurals>
<plurals name="certify_keys_with_errors">
<item quantity="one">Оверавање није успело!</item>
<item quantity="few">Оверавање није успело за %d кључа!</item>
@@ -584,7 +545,6 @@
</plurals>
<string name="key_list_empty_text1">Нема нађених кључева!</string>
<string name="key_list_filter_show_all">Прикажи све кључеве</string>
- <string name="key_list_filter_show_certified">Прикажи само оверене кључеве</string>
<!--Key view-->
<string name="key_view_action_edit">Уреди кључ</string>
<string name="key_view_action_encrypt">Шифруј текст</string>
@@ -601,23 +561,11 @@
<string name="key_view_tab_keybase">Keybase.io</string>
<string name="user_id_info_revoked_title">Опозван</string>
<string name="user_id_info_revoked_text">Власник кључа је опозвао овај идентитет. Више није исправан.</string>
- <string name="user_id_info_certified_title">Оверен</string>
- <string name="user_id_info_certified_text">Овај идентитет сте ви оверили.</string>
- <string name="user_id_info_uncertified_title">Није оверен</string>
- <string name="user_id_info_uncertified_text">Овај идентитет још није оверен. Не можете бити сигурни да идентитет заиста одговара одређеној особи.</string>
<string name="user_id_info_invalid_title">Неисправан</string>
<string name="user_id_info_invalid_text">Нешто није у реду са овим идентитетом!</string>
<!--Key trust-->
- <string name="key_trust_already_verified">Већ сте потврдили овај кључ!</string>
- <string name="key_trust_it_is_yours">Ово је један од ваших кључева!</string>
- <string name="key_trust_maybe">Кључ није ни опозван нити је истекао.\nЈош га нисте потврдили, али можете да се поуздате у њега ако желите.</string>
- <string name="key_trust_revoked">Власник је опозвао овај кључ. Не бисте требали да се поуздате у њега.</string>
- <string name="key_trust_expired">Овај кључ је истекао. Не бисте требали да се поуздате у њега.</string>
- <string name="key_trust_old_keys">Можда је у реду користити овај кључ за дешифровање старе поруке из времена кад је био важећи.</string>
- <string name="key_trust_no_cloud_evidence">Нема доказа са клауда о поузданости овог кључа.</string>
<string name="key_trust_start_cloud_search">Почни претрагу</string>
<string name="key_trust_results_prefix">Keybase.io нуди „доказе“ који потврђују да власник овог кључа: </string>
- <string name="key_trust_header_text">Напомена: Докази са Keybase.io су експериментална функција Отвореног кључарника. Препорука је да очитавате бар-кôдове или размењујете кључеве преко НФЦ-а како бисте их потврдили.</string>
<!--keybase proof stuff-->
<string name="keybase_narrative_twitter">Објављује на Твитеру као %s</string>
<string name="keybase_narrative_github">Познат је на Гитхабу као %s</string>
@@ -675,7 +623,6 @@
<string name="edit_key_error_bad_nfc_size">Смарт картица не подржава ову величину кључа!</string>
<string name="edit_key_error_bad_nfc_stripped">Не могу да преместим кључ на смарт картицу (или је огољен или је „преусмери-на-картицу“)!</string>
<!--Create key-->
- <string name="create_key_upload">Синхронизуј са клаудом</string>
<string name="create_key_empty">Ово поље је обавезно</string>
<string name="create_key_passphrases_not_equal">Лозинке се не поклапају</string>
<string name="create_key_final_text">Унели сте следећи идентитет:</string>
@@ -691,12 +638,9 @@
<string name="create_key_add_email_text">Додатне е-адресе се такође односе на овај кљул и могу да се користе за безбедну комуникацију.</string>
<string name="create_key_email_already_exists_text">Е-адреса је већ додата</string>
<string name="create_key_email_invalid_email">Формат е-адресе није исправан</string>
- <string name="create_key_yubi_key_pin_text">Запамтите ПИН, биће вам потребан за касније коришћење Јубикључа. Запишите администраторски ПИН и сачувајте га на безбедном месту.</string>
<string name="create_key_yubi_key_pin">ПИН</string>
<string name="create_key_yubi_key_admin_pin">Администраторски ПИН</string>
- <string name="create_key_yubi_key_pin_repeat_text">Унесите ПИН и администраторски ПИН да бисте наставили.</string>
<string name="create_key_yubi_key_pin_repeat">Поновите ПИН</string>
- <string name="create_key_yubi_key_admin_pin_repeat">Поновите администраторски ПИН</string>
<string name="create_key_yubi_key_pin_not_correct">ПИН није тачан!</string>
<!--View key-->
<string name="view_key_revoked">Опозван: кључ више не смије бити коришћен!</string>
@@ -709,10 +653,8 @@
<!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Додај сервер кључева</string>
<string name="edit_keyserver_dialog_title">Промени сервер кључева</string>
- <string name="add_keyserver_verified">Сервер кључева оверен!</string>
<string name="add_keyserver_without_verification">Сервер кључева додат без оверивања.</string>
<string name="add_keyserver_invalid_url">Неисправан УРЛ!</string>
- <string name="add_keyserver_connection_failed">Неуспех повезивања са сервером кључева. Проверите УРЛ и вашу везу са интернетом.</string>
<string name="keyserver_preference_deleted">%s обрисан</string>
<string name="keyserver_preference_cannot_delete_last">Не могу да обришем последњи сервер кључева. Потребан је бар један!</string>
<!--Navigation Drawer-->
@@ -722,7 +664,6 @@
<string name="drawer_open">Отвори навигациону фиоку</string>
<string name="drawer_close">Затвори навигациону фиоку</string>
<string name="my_keys">Моји кључеви</string>
- <string name="nav_backup">Резерва</string>
<!--hints-->
<string name="encrypt_content_edit_text_hint">Укуцајте текст</string>
<!--certs-->
@@ -772,7 +713,6 @@
<string name="msg_ip_master_flags_xxxa">Заставице главног: аутентификовање</string>
<string name="msg_ip_master_flags_xxxx">Заставице главног: ниједна</string>
<string name="msg_ip_merge_public">Спајам увезене податке у постојећи јавни привезак</string>
- <string name="msg_ip_merge_secret">Спајам увезене податке у постојећи јавни привезак</string>
<string name="msg_ip_subkey">Обрађујем поткључ %s</string>
<string name="msg_ip_subkey_expired">Поткључ је истекао %s</string>
<string name="msg_ip_subkey_expires">Поткључ истиче %s</string>
@@ -841,7 +781,6 @@
<string name="msg_is_importing_subkeys">Обрађујем тајне поткључеве</string>
<string name="msg_is_error_io_exc">Грешка кодирања привеска</string>
<string name="msg_is_merge_public">Спајам увезене податке у постојећи јавни привезак</string>
- <string name="msg_is_merge_secret">Спајам увезене податке у постојећи јавни привезак</string>
<string name="msg_is_merge_special">Спајам податке сопствених сертификата из јавног привеска</string>
<string name="msg_is_pubring_generate">Генеришем јавни привезак од тајног привеска</string>
<string name="msg_is_subkey_nonexistent">Поткључ %s није доступан у тајном кључу</string>
@@ -944,7 +883,6 @@
<string name="msg_cr_error_no_user_id">Привесци морају садржати бар један кориснички ИД!</string>
<string name="msg_cr_error_no_certify">Главни кључ мора имати заставицу овере!</string>
<string name="msg_cr_error_null_expiry">Датум истицања не може бити „исти као пре“ на стварању кључа. Ово је грешка у програмирању, поднесите извештај о грешци!</string>
- <string name="msg_cr_error_keysize_512">Величина кључа мора бити већа или једнака 512!</string>
<string name="msg_cr_error_no_curve">Није наведена величина кључа! Ово је грешка у програмирању, поднесите извештај о грешци!</string>
<string name="msg_cr_error_no_keysize">Није наведена елиптичка крива! Ово је грешка у програмирању, поднесите извештај о грешци!</string>
<string name="msg_cr_error_internal_pgp">Унутрашња ОпенПГП грешка!</string>
@@ -1110,8 +1048,6 @@
<string name="msg_dc_insecure_key">Небезбедан кључ: или је дужина РСА/ДСА/Елгамал кључа прекратка или је ЕЦЦ кривуља/алгоритам сматрана небезбедном! Ово може да се деси ако је апликација застарела, или услед напада.</string>
<!--Messages for VerifySignedLiteralData operation-->
<string name="msg_vl">Почињем проверу потписа</string>
- <string name="msg_vl_error_no_siglist">Нема списка потписа у потписаним дословним подацима</string>
- <string name="msg_vl_error_wrong_key">Порука није потписана правим кључем</string>
<string name="msg_vl_error_missing_literal">Нема корисних података у потписаним дословним подацима</string>
<string name="msg_vl_clear_meta_file">Име фајла: %s</string>
<string name="msg_vl_clear_meta_mime">МИМЕ тип: %s</string>
@@ -1131,7 +1067,6 @@
<string name="msg_se_success">Радња потписивања/шифровања је успела!</string>
<!--Messages for PgpSignEncrypt operation-->
<string name="msg_pse_asymmetric">Припремам јавне кључеве за шифровање</string>
- <string name="msg_pse_clearsign_only">Потписивање обичног текста није подржано!</string>
<string name="msg_pse_compressing">Припремам компресију</string>
<string name="msg_pse_encrypting">Шифрујем податке</string>
<string name="msg_pse_error_bad_passphrase">Нетачна лозинка!</string>
@@ -1190,39 +1125,15 @@
<string name="msg_import_fetch_error_decode">Грешка декодирања добављеног привеска!</string>
<string name="msg_import_fetch_error">Не могу да добавим кључ! (Проблеми са мрежом?)</string>
<string name="msg_import_fetch_keybase">Добављам са keybase.io: %s</string>
- <string name="msg_import_fetch_error_keyserver">Не могу да добавим кључ са сервера кључева: %s</string>
<string name="msg_import_fetch_keyserver">Добављам са сервера кључева: %s</string>
<string name="msg_import_fetch_keyserver_ok">Добављање кључева је успело</string>
<string name="msg_import_keyserver">Користим сервер кључева %s</string>
- <string name="msg_import_fingerprint_error">Отисак добављеног кључа не одговара очекиваном!</string>
- <string name="msg_import_fingerprint_ok">Провера отиска је у реду</string>
<string name="msg_import_merge">Спајам добављене податке</string>
<string name="msg_import_merge_error">Грешка спајања добављених података!</string>
<string name="msg_import_error">Радња увоза није успела!</string>
<string name="msg_import_error_io">Радња увоза није успела због У/И грешке!</string>
<string name="msg_import_partial">Радња увоза је успела, са грешкама!</string>
<string name="msg_import_success">Радња увоза је успела!</string>
- <plurals name="msg_export">
- <item quantity="one">Извозим један кључ</item>
- <item quantity="few">Извозим %d кључа</item>
- <item quantity="other">Извозим %d кључева</item>
- </plurals>
- <string name="msg_export_file_name">Име фајла: %s</string>
- <string name="msg_export_all">Извозим све кључеве</string>
- <string name="msg_export_public">Извозим јавни кључ %s</string>
- <string name="msg_export_upload_public">Отпремам јавни кључ %s</string>
- <string name="msg_export_secret">Извозим тајни кључ %s</string>
- <string name="msg_export_error_no_file">Није наведено име фајла!</string>
- <string name="msg_export_error_fopen">Грешка отварања фајла!</string>
- <string name="msg_export_error_no_uri">Није наведен УРИ!</string>
- <string name="msg_export_error_uri_open">Грешка отварања УРИ тока!</string>
- <string name="msg_export_error_storage">Складиште није спремно за уписивање!</string>
- <string name="msg_export_error_db">Грешка базе података!</string>
- <string name="msg_export_error_io">Грешка улаза/излаза!</string>
- <string name="msg_export_error_key">Грешка предобраде података кључа!</string>
- <string name="msg_export_error_upload">Грешка отпремања кључа на сервер. Проверите вашу везу са интернетом.</string>
- <string name="msg_export_success">Радња извоза је успела</string>
- <string name="msg_export_upload_success">Отпремање на сервер кључева је успело</string>
<string name="msg_del_error_empty">Нема ништа за брисање!</string>
<string name="msg_del_error_multi_secret">Тајне кључеве можете брисати само појединачно!</string>
<plurals name="msg_del">
@@ -1248,6 +1159,9 @@
<string name="msg_revoke_key">Опозивам кључ %s</string>
<string name="msg_revoke_key_fail">Неуспех опозивања кључа</string>
<string name="msg_revoke_ok">Успешно опозван кључ</string>
+ <!--Linked Identity verification-->
+ <string name="msg_lv_fetch_error_io">У/И грешка!</string>
+ <string name="msg_lv_fetch_error_format">Грешка формата!</string>
<string name="msg_acc_saved">Налог је сачуван</string>
<string name="msg_download_success">Успешно преузето!</string>
<string name="msg_download_no_valid_keys">Нема исправних кључева у фајлу/клипборду!</string>
@@ -1269,12 +1183,7 @@
<string name="msg_keybase_error_dns_fail">Добављање ДНС ТЕКСТ записа није успело</string>
<string name="msg_keybase_error_specific">%s</string>
<string name="msg_keybase_error_msg_payload_mismatch">Дешифрована објава доказа се не поклапа са очекиваном вредношћу</string>
- <!--Messages for Export Log operation-->
- <string name="msg_export_log_start">Извозим дневник</string>
- <string name="msg_export_log_error_fopen">Грешка отварања фајла</string>
- <string name="msg_export_log_error_no_file">Није наведено име фајла!</string>
- <string name="msg_export_log_error_writing">У/И грешка уписа у фајл!</string>
- <string name="msg_export_log_success">Дневник успешно извезен!</string>
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<string name="passp_cache_notif_click_to_clear">Тапните да очистите лозинке.</string>
<plurals name="passp_cache_notif_n_keys">
@@ -1286,7 +1195,6 @@
<string name="passp_cache_notif_clear">Очисти лозинке</string>
<string name="passp_cache_notif_pwd">Лозинка</string>
<!--Keyserver sync-->
- <string name="keyserver_sync_orbot_notif_title">Синхронизација са облака захтева Орбот</string>
<string name="keyserver_sync_orbot_notif_msg">Тапните да бисте покренули Орбот</string>
<string name="keyserver_sync_orbot_notif_start">Покрени Орбот</string>
<string name="keyserver_sync_orbot_notif_ignore">Директно</string>
@@ -1306,13 +1214,11 @@
<string name="section_certifier_id">Сертификатор</string>
<string name="section_cert">Детаљи сертификата</string>
<string name="label_user_id">Идентитет</string>
- <string name="unknown_uid">&lt;непознат&gt;</string>
+ <string name="unknown_uid"><![CDATA[<непознато>]]></string>
<string name="empty_certs">Нема сертификата за овај кључ</string>
<string name="certs_text">Приказани су само потврђени сопствени сертификати и потврђени сертификати направљени вашим кључем.</string>
<string name="section_uids_to_certify">Идентитети за</string>
<string name="certify_text">Кључеви које увозите садрже „идентитете“: имена и е-адресе. Одредите за потврду само оне који одговарају ономе што очекујете.</string>
- <string name="certify_fingerprint_text">Упоредите приказани отисак, знак по знак, са оним приказаним на другаревом уређају.</string>
- <string name="certify_fingerprint_text2">Да ли се приказани отисци поклапају?</string>
<string name="label_revocation">Разлог опозива</string>
<string name="label_cert_type">Тип</string>
<string name="error_key_not_found">Кључ није нађен!</string>
@@ -1372,7 +1278,7 @@
<string name="button_bind_key">Повежи кључ</string>
<string name="yubikey_serno">Серијски број: %s</string>
<string name="yubikey_key_holder">Власник кључа: </string>
- <string name="yubikey_key_holder_not_set">Власник кључа: &lt;није постављен&gt;</string>
+ <string name="yubikey_key_holder_not_set"><![CDATA[Држач кључа: <није постављено>]]></string>
<string name="yubikey_status_bound">Јубикључ одговара и повезан са кључем</string>
<string name="yubikey_status_unbound">Јубикључ одговара, може да се повеже са кључем</string>
<string name="yubikey_status_partly">Јубикључ одговара, делимично повезан са кључем</string>
@@ -1397,7 +1303,6 @@
<string name="error_nfc_header">Јубикључ је пријавио неисправан %s бит.</string>
<string name="error_nfc_tag_lost">Јубикључ је прерано склоњен. Држите Јубикључ на полеђини уређаја док се радња не заврши.</string>
<string name="error_nfc_try_again">Покушај поново</string>
- <string name="error_pin_nodefault">Подразумевани ПИН је одбијен!</string>
<string name="error_temp_file">Грешка стварања привременог фајла.</string>
<string name="btn_delete_original">Обриши оригинални фајл</string>
<string name="snack_encrypt_filenames_on">Имена фајлова <b>су</b> шифрована.</string>
@@ -1409,8 +1314,6 @@
<string name="error_loading_keys">Грешка учитавања кључева!</string>
<string name="error_empty_log">(грешка, празан дневник)</string>
<string name="error_reading_text">Не могу да очитам унос за дешифровање!</string>
- <string name="filename_unknown">&lt;нема имена&gt;</string>
- <string name="filename_unknown_text">&lt;обични текстуални подаци&gt;</string>
<string name="intent_show">Прикажи потписани/шифровани садржај</string>
<string name="view_internal">Прикажи у Отвореном кључарнику</string>
<string name="error_preparing_data">Грешка припремања података!</string>
@@ -1426,4 +1329,25 @@
<string name="error_scan_fp">Грешка очитавања отиска!</string>
<string name="error_scan_match">Отисци се не поклапају!</string>
<string name="error_expiry_past">Датум истицања је у прошлости!</string>
+ <string name="linked_create_https_1_4">На пример: https://example.com/pgpkey.txt</string>
+ <string name="linked_create_verify">Овери</string>
+ <string name="linked_text_clipboard">Текст је копиран на клипборд</string>
+ <!--Other Linked Identity strings-->
+ <string name="linked_verifying">Оверавам…</string>
+ <string name="menu_linked_add_identity">Повежи са налогом</string>
+ <string name="section_linked_identities">Повезани идентитети</string>
+ <string name="btn_finish">Заврши</string>
+ <string name="linked_title_https">Вебсајт (HTTPS)</string>
+ <string name="linked_title_dns">Име домене (DNS)</string>
+ <string name="linked_title_github">Гитхаб</string>
+ <string name="linked_title_twitter">Твитер</string>
+ <string name="card_linked_identity">Повезани идентитет</string>
+ <string name="linked_button_verify">Овери</string>
+ <string name="linked_button_retry">Покушај поново</string>
+ <string name="linked_button_confirm">Потврди</string>
+ <string name="linked_button_view">Приказ</string>
+ <string name="linked_text_verifying">Оверавам…</string>
+ <string name="linked_text_error">Грешка</string>
+ <string name="linked_text_confirming">Потврђујем…</string>
+ <string name="title_linked_id_create">Направи повезани идентитет</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-sv/strings.xml b/OpenKeychain/src/main/res/values-sv/strings.xml
index 1ccac9199..0d44b6415 100644
--- a/OpenKeychain/src/main/res/values-sv/strings.xml
+++ b/OpenKeychain/src/main/res/values-sv/strings.xml
@@ -9,6 +9,7 @@
<string name="title_decrypt">Dekryptera</string>
<string name="title_add_subkey">Lägg till undernyckel</string>
<string name="title_edit_key">Redigera nyckel</string>
+ <string name="title_linked_create">Skapa en länkad identitet</string>
<string name="title_preferences">Inställningar</string>
<string name="title_api_registered_apps">Appar</string>
<string name="title_key_server_preference">OpenPGP-nyckelservrar</string>
@@ -20,6 +21,8 @@
<string name="title_encrypt_to_file">Kryptera till fil</string>
<string name="title_decrypt_to_file">Dekryptera till fil</string>
<string name="title_import_keys">Importera nycklar</string>
+ <string name="title_export_key">Säkerhetskopiera nyckel</string>
+ <string name="title_export_keys">Säkerhetskopiera nycklar</string>
<string name="title_key_not_found">Nyckel hittades inte</string>
<string name="title_send_key">Ladda upp till nyckelserver</string>
<string name="title_certify_key">Bekräfta nyckel</string>
@@ -29,29 +32,35 @@
<string name="title_exchange_keys">Utbyt nycklar</string>
<string name="title_advanced_key_info">Förlängd information</string>
<string name="title_delete_secret_key">Radera DIN nyckel \'%s\'?</string>
- <string name="title_export_log">Exportera logg</string>
<string name="title_manage_my_keys">Hantera mina nycklar</string>
<!--section-->
<string name="section_user_ids">Identiteter</string>
<string name="section_yubikey">YubiKey</string>
<string name="section_linked_system_contact">Länkade systemkontakten</string>
+ <string name="section_keybase_proofs">Keybase.io-bevis</string>
<string name="section_should_you_trust">Skulle du lita på denna nyckel?</string>
<string name="section_proof_details">Bevisverifiering</string>
- <string name="section_cloud_evidence">Bevis från molnet</string>
<string name="section_keys">Undernycklar</string>
- <string name="section_cloud_search">Molnsökning</string>
+ <string name="section_cloud_search">Nyckelsökning</string>
+ <string name="section_cloud_search_summary">Nyckelserver, keybase.io</string>
+ <string name="section_proxy_settings_summary">Tor, proxyinställningar</string>
+ <string name="section_gui">Gränssnitt</string>
<string name="section_certify">Bekräfta</string>
<string name="section_actions">Åtgärder</string>
<string name="section_share_key">Nyckel</string>
<string name="section_key_server">Nyckelserver</string>
<string name="section_fingerprint">Fingeravtryck</string>
<string name="section_encrypt">Kryptera</string>
+ <string name="section_decrypt">Dekryptera / Verifiera</string>
<string name="section_current_expiry">Aktuellt utgångsdatum</string>
<string name="section_new_expiry">Nytt utgångsdaum</string>
<!--button-->
<string name="btn_decrypt_verify_file">Dekryptera, verifiera och spara fil</string>
<string name="btn_encrypt_share_file">Kryptera och dela fil</string>
<string name="btn_encrypt_save_file">Kryptera och spara fil</string>
+ <string name="btn_save_file">Spara fil</string>
+ <string name="btn_save">Spara</string>
+ <string name="btn_view_log">Visa logg</string>
<string name="btn_do_not_save">Avbryt</string>
<string name="btn_delete">Radera</string>
<string name="btn_no_date">Inget utgångsdatum</string>
@@ -61,13 +70,13 @@
<string name="btn_back">Föregående</string>
<string name="btn_no">Nej</string>
<string name="btn_match">Fingeravtrycken matchar</string>
- <string name="btn_share_encrypted_signed">Kryptera och dela text</string>
- <string name="btn_copy_encrypted_signed">Kryptera och kopiera text</string>
+ <string name="btn_share_encrypted_signed">Kryptera/signera och dela text</string>
+ <string name="btn_copy_encrypted_signed">Kryptera/signera och kopiera text</string>
<string name="btn_view_cert_key">Visa nyckel för certifiering</string>
<string name="btn_create_key">Skapa nyckel</string>
<string name="btn_add_files">Lägg till fil(er)</string>
- <string name="btn_share_decrypted_text">Dela dekrypterad text</string>
<string name="btn_copy_decrypted_text">Kopiera dekrypterad text</string>
+ <string name="btn_decrypt_clipboard">Läs från urklipp</string>
<string name="btn_encrypt_files">Kryptera filer</string>
<string name="btn_encrypt_text">Kryptera text</string>
<string name="btn_add_email">Lägg till extra e-postadress</string>
@@ -88,8 +97,7 @@
<string name="menu_export_all_keys">Exportera alla nycklar</string>
<string name="menu_update_all_keys">Uppdatera alla nycklar</string>
<string name="menu_advanced">Utökad information</string>
- <string name="menu_certify_fingerprint">Bekräfta via fingeravtrycksjämförelse</string>
- <string name="menu_export_log">Exportera logg</string>
+ <string name="menu_keyserver_add">Lägg till</string>
<!--label-->
<string name="label_message">Text</string>
<string name="label_file">Fil</string>
@@ -105,9 +113,8 @@
<string name="label_file_ascii_armor">Aktivera ASCII-format</string>
<string name="label_write_version_header">Låt andra se att du använder OpenKeychain</string>
<string name="label_write_version_header_summary">Skriver \'OpenKeychain v2.7\' till OpenPGP-signaturer, chiffertext och exporterade nycklar.</string>
- <string name="label_use_default_yubikey_pin">Använd förvald YubiKey PIN</string>
<string name="label_use_num_keypad_for_yubikey_pin">Använd numeriska tangentbordet för YubiKey PIN</string>
- <string name="label_label_use_default_yubikey_pin_summary">Använder förvald PIN (123456) för att få åtkomst till YubiKeys via NFC</string>
+ <string name="label_asymmetric_from">Signera med:</string>
<string name="label_to">Kryptera till:</string>
<string name="label_delete_after_encryption">Radera filer efter kryptering</string>
<string name="label_delete_after_decryption">Radera efter dekryptering</string>
@@ -128,27 +135,40 @@
<string name="label_name">Namn</string>
<string name="label_comment">Kommentar</string>
<string name="label_email">E-post</string>
- <string name="label_send_key">Synkronisera med molnet</string>
<string name="label_fingerprint">Fingeravtryck</string>
<string name="expiry_date_dialog_title">Ställ in utgångsdatum</string>
+ <string name="label_keyservers_title">Nyckelservrar</string>
<string name="label_preferred">föredraget</string>
<string name="label_enable_compression">Aktivera kompression</string>
<string name="label_encrypt_filenames">Kryptera filnamn</string>
<string name="label_hidden_recipients">Dölj mottagare</string>
- <string name="label_verify_keyserver">Verifiera nyckelserver</string>
- <string name="label_enter_keyserver_url">Ange nyckelserver-URL</string>
+ <string name="label_keyserver_dialog_delete">Radera nyckelserver</string>
+ <string name="label_theme">Tema</string>
<string name="pref_keyserver">OpenPGP nyckelservrar</string>
<string name="pref_keyserver_summary">Sök nycklar på valda OpenPGP nyckelservrar (HKP-protokollet)</string>
<string name="pref_keybase">keybase.io</string>
<string name="pref_keybase_summary">Sök nycklar på keybase.io</string>
+ <string name="label_sync_settings_keyserver_title">Uppdatera nycklar automatiskt</string>
+ <string name="label_sync_settings_keyserver_summary_off">Nycklar uppdateras inte automatiskt</string>
<!--label shown in Android settings under the OpenKeychain account-->
+ <string name="keyserver_sync_settings_title">Uppdatera nycklar automatiskt</string>
+ <string name="label_experimental_settings_desc_title">Varning</string>
+ <string name="label_experimental_settings_linked_identities_title">Länkade identiteter</string>
+ <string name="label_experimental_settings_keybase_title">Keybase.io-bevis</string>
<!--Proxy Preferences-->
+ <string name="pref_proxy_tor_title">Aktivera Tor</string>
+ <string name="pref_proxy_type_title">Proxytyp</string>
<!--proxy type choices and values-->
+ <string name="pref_proxy_type_choice_http">HTTP</string>
<!--OrbotHelper strings-->
<!--InstallDialogFragment strings-->
+ <string name="orbot_install_dialog_title">Installera Orbot för att använda Tor?</string>
+ <string name="orbot_install_dialog_install">Installera</string>
+ <string name="orbot_install_dialog_cancel">Avbryt</string>
<!--StartOrbotDialogFragment strings-->
- <string name="user_id_no_name">&lt;inget namn&gt;</string>
- <string name="none">&lt;ingen&gt;</string>
+ <string name="orbot_start_dialog_title">Starta Orbot?</string>
+ <string name="orbot_start_btn">Starta Orbot?</string>
+ <string name="orbot_start_dialog_start">Starta Orbot?</string>
<plurals name="n_keys">
<item quantity="one">1 nyckel</item>
<item quantity="other">%d nycklar</item>
@@ -190,7 +210,6 @@
<string name="no_filemanager_installed">Ingen kompatibel filhanterare är installerad.</string>
<string name="passphrases_do_not_match">Lösenorden stämde inte överens.</string>
<string name="passphrase_must_not_be_empty">Var god ange ett lösenord.</string>
- <string name="passphrase_for_symmetric_encryption">Symmetrisk kryptering.</string>
<string name="passphrase_for">Ange lösenord för \'%s\'</string>
<string name="pin_for">Ange PIN för \'%s\'</string>
<string name="yubikey_pin_for">Ange PIN för att få åtkomst till YubiKey för \'%s\'</string>
@@ -203,7 +222,6 @@
<string name="specify_file_to_encrypt_to">Ange vilken fil du vill kryptera till.\nVARNING: Om filen redan finns kommer den att skrivas över!</string>
<string name="specify_file_to_decrypt_to">Ange vilken fil du vill kryptera till.\nVARNING: Om filen redan finns kommer den att skrivas över!</string>
<string name="key_deletion_confirmation_multi">Vill du verkligen radera alla markerade nycklar?</string>
- <string name="secret_key_deletion_confirmation">Efter radering kommer du inte kunna läsa meddelande krypterade med den här nyckeln samt förlora alla nyckelbekräftningar som gjorts med den!</string>
<string name="public_key_deletetion_confirmation">Radera nyckel \'%s\'?</string>
<string name="also_export_secret_keys">Exportera även privata nycklar</string>
<string name="reinstall_openkeychain">Du stötte på en känd bugg hos Android. Installera om OpenKeychain om du vill koppla ihop dina kontaker med nycklar.</string>
@@ -212,7 +230,6 @@
<string name="no_keys_exported">Inga nycklar exporterades.</string>
<string name="key_creation_el_gamal_info">Obs: endast undernycklar har stöd för ElGamal.</string>
<string name="key_not_found">Kunde inte hitta nyckeln %08X.</string>
- <string name="specify_file_to_export_log_to">Ange en fil att exportera till. \nVARNING: Filen kommer skrivas över om den redan existerar.</string>
<plurals name="bad_keys_encountered">
<item quantity="one">%d dålig privat nyckel hoppades över. Du kanske exporterade med alternativet \n --export-secret-subkeys\nSe till att du exporterar med\n --export-secret-keys\nistället.\"</item>
<item quantity="other">%d dåliga privata nycklar hoppades över. Du kanske exporterade med alternativet \n --export-secret-subkeys\nSe till att du exporterar med\n --export-secret-keys\nistället.\"</item>
@@ -222,7 +239,6 @@
<string name="key_copied_to_clipboard">Nyckel har kopierats till urklipp!</string>
<string name="fingerprint_copied_to_clipboard">Fingeravtryck har kopierats till urklipp!</string>
<string name="select_key_to_certify">Välj en nyckel att använda för bekräftning!</string>
- <string name="key_too_big_for_sharing">Nyckeln är för stor för att dela på detta sätt!</string>
<string name="text_copied_to_clipboard">Text har kopierats till urklipp!</string>
<!--errors
no punctuation, all lowercase,
@@ -257,6 +273,7 @@
<string name="decrypt_result_signature_certified">Signerat av bekräftad nyckel</string>
<string name="decrypt_result_encrypted">Krypterat</string>
<string name="decrypt_result_not_encrypted">Inte krypterat</string>
+ <string name="decrypt_result_insecure">Osäker kryptering</string>
<string name="decrypt_result_action_show">Visa</string>
<string name="decrypt_result_action_Lookup">Sök efter</string>
<string name="decrypt_invalid_button">Jag förstår riskerna, visa den!</string>
@@ -268,6 +285,7 @@
<string name="progress_cancelling">avbryter…</string>
<string name="progress_saving">sparar…</string>
<string name="progress_importing">importerar…</string>
+ <string name="progress_revoking_uploading">Återkallar och laddar upp nyckel…</string>
<string name="progress_updating">Uppdaterar nycklar...</string>
<string name="progress_exporting">exporterar…</string>
<string name="progress_uploading">laddar upp…</string>
@@ -300,8 +318,8 @@
<string name="progress_encrypting">krypterar data…</string>
<string name="progress_decrypting">dekrypterar data…</string>
<string name="progress_preparing_signature">förebereder signatur…</string>
- <string name="progress_generating_signature">genererar signatur…</string>
<string name="progress_processing_signature">bearbetar signatur…</string>
+ <string name="progress_generating_signature">genererar signatur…</string>
<string name="progress_verifying_signature">verifierar signatur…</string>
<string name="progress_signing">signerar…</string>
<string name="progress_certifying">certifierar…</string>
@@ -313,14 +331,10 @@
<string name="progress_deleting">raderar nycklar…</string>
<string name="progress_con_saving">konsolidera: sparar till cache…</string>
<string name="progress_con_reimport">konsolidera: återimporterar…</string>
- <string name="progress_verifying_keyserver_url">verifierar nyckelserver...</string>
+ <string name="progress_starting_orbot">Startar Orbot…</string>
<!--action strings-->
<string name="hint_cloud_search_hint">Söker via Namn, E-post...</string>
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -350,7 +364,7 @@
<string name="help_about_version">Version:</string>
<!--Import-->
<string name="import_tab_keyserver">Nyckelserver</string>
- <string name="import_tab_cloud">Sök i molnet</string>
+ <string name="import_tab_cloud">Nyckelsökning</string>
<string name="import_tab_direct">Fil/urklipp</string>
<string name="import_tab_qr_code">QR-kod/NFC</string>
<string name="import_import">Importera markerade nycklar</string>
@@ -363,14 +377,6 @@
<string name="with_warnings">, med varningar</string>
<string name="with_cancelled">, tills det avbryts</string>
<!--Import result toast-->
- <plurals name="import_keys_added_and_updated_1">
- <item quantity="one">Importerade nyckel</item>
- <item quantity="other">Importerade %1$d nycklar</item>
- </plurals>
- <plurals name="import_keys_added_and_updated_2">
- <item quantity="one">och uppdaterade nyckel%2$s.</item>
- <item quantity="other">och uppdaterade %1$d nycklar%2$s.</item>
- </plurals>
<plurals name="import_keys_added">
<item quantity="one">Importerade nyckel%2$s.</item>
<item quantity="other">Importerade %1$d nycklar%2$s.</item>
@@ -410,10 +416,6 @@
<string name="delete_cancelled">Raderingsoperation avbruten.</string>
<!--Revoke result toast (snackbar)-->
<!--Certify result toast-->
- <plurals name="certify_keys_ok">
- <item quantity="one">Certifierade nyckel%2$s.</item>
- <item quantity="other">Certifierade %1$d nycklar%2$s.</item>
- </plurals>
<plurals name="certify_keys_with_errors">
<item quantity="one">Certifiering misslyckades!</item>
<item quantity="other">Certifiering misslyckades för %d nycklar!</item>
@@ -472,7 +474,9 @@
</plurals>
<string name="key_list_empty_text1">Inga nycklar hittades!</string>
<string name="key_list_filter_show_all">Visa alla nycklar</string>
- <string name="key_list_filter_show_certified">Visa endast certifierade nycklar</string>
+ <string name="key_list_fab_qr_code">Skanna QR-kod</string>
+ <string name="key_list_fab_search">Nyckelsökning</string>
+ <string name="key_list_fab_import">Importera från fil</string>
<!--Key view-->
<string name="key_view_action_edit">Redigera nyckel</string>
<string name="key_view_action_encrypt">Kryptera text</string>
@@ -489,24 +493,15 @@
<string name="key_view_tab_keybase">Keybase.io</string>
<string name="user_id_info_revoked_title">Återkallad</string>
<string name="user_id_info_revoked_text">Den här identiteten har återkallats av nyckelns ägare. Den är inte längre giltig.</string>
- <string name="user_id_info_certified_title">Certifierad</string>
- <string name="user_id_info_certified_text">Den här identiteten har certifierats av dig.</string>
- <string name="user_id_info_uncertified_title">Inte certifierad.</string>
- <string name="user_id_info_uncertified_text">Den här identiteten har ännu inte certifierats. Du kan inte vara säker på att identiteten verkligen hänger ihop med en viss person.</string>
+ <string name="user_id_info_certified_title">Bekräftad</string>
+ <string name="user_id_info_uncertified_title">Inte bekräftad</string>
<string name="user_id_info_invalid_title">Ogiltig</string>
<string name="user_id_info_invalid_text">Något är fel med den här identiteten!</string>
<!--Key trust-->
- <string name="key_trust_already_verified">Du har redan bekräftat den här nyckeln!</string>
- <string name="key_trust_it_is_yours">Det här är en av dina nycklar!</string>
- <string name="key_trust_maybe">Den här nyckeln är varken återkallad eller utgången.\nDu har inte bekräftat den, men du kan välja att lita på den.</string>
- <string name="key_trust_revoked">Den här nyckeln har återkallats av sin ägare. Du borde inte lita på den.</string>
- <string name="key_trust_expired">Den här nyckeln har gått ut. Du borde inte lita på den.</string>
- <string name="key_trust_old_keys">Det kan vara okej att använda den här för att avkryptera ett gammalt medelande från tiden när den här nyckeln var giltig.</string>
- <string name="key_trust_no_cloud_evidence">Inget bevis från molnet angående den här nyckelns trovärdighet.</string>
<string name="key_trust_start_cloud_search">Påbörja sökning</string>
<string name="key_trust_results_prefix">Keybase.io erbjuder \"bevis\" som hävdar att ägaren av den här nyckeln:</string>
- <string name="key_trust_header_text">Observera: Keybase.io bevis är en experimentell funktion i OpenKeychain. Vi uppmanar dig att skanna QR-koder eller utbyta nycklar via NFC utöver att bekräfta dem.</string>
<!--keybase proof stuff-->
+ <string name="keybase_narrative_github">Är känd på GitHub som %s</string>
<string name="keybase_proof_failure">Tyvärr kan detta bevis inte verifieras.</string>
<string name="keybase_problem_fetching_evidence">Problem med bevis</string>
<string name="keybase_dns_query_failure">Hämtning av DNS TXT-post misslyckades</string>
@@ -540,7 +535,6 @@
<string name="edit_key_error_bad_nfc_algo">Algoritmen stöds inte av smartcard!</string>
<string name="edit_key_error_bad_nfc_size">Nyckelstorleken stöds inte av smartcard!</string>
<!--Create key-->
- <string name="create_key_upload">Synkronisera med molnet</string>
<string name="create_key_empty">Detta fält krävs</string>
<string name="create_key_passphrases_not_equal">Lösenorden stämmer inte överens</string>
<string name="create_key_final_text">Du angav följande identitet:</string>
@@ -565,10 +559,8 @@
<string name="view_key_fragment_no_system_contact">&lt;ingen&gt;</string>
<!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">Lägg till nyckelserver</string>
- <string name="add_keyserver_verified">Nyckelserver verifierad!</string>
<string name="add_keyserver_without_verification">Nyckelserver tillagd utan verifiering.</string>
<string name="add_keyserver_invalid_url">Ogiltig URL!</string>
- <string name="add_keyserver_connection_failed">Misslyckades med att ansluta till nyckelserver. Kontrollera URL:en och din internetanslutning.</string>
<!--Navigation Drawer-->
<string name="nav_keys">Nycklar</string>
<string name="nav_encrypt_decrypt">Kryptera/dekryptera</string>
@@ -620,7 +612,6 @@
<string name="msg_ip_master_flags_xxxa">Huvudflaggor: autentisera</string>
<string name="msg_ip_master_flags_xxxx">Huvudflaggor: ingen</string>
<string name="msg_ip_merge_public">Slår ihop importerade data med befintlig publik nyckelring</string>
- <string name="msg_ip_merge_secret">Slår ihop importerade data med befintlig publik nyckelring</string>
<string name="msg_ip_subkey">Bearbetar undernyckel %s</string>
<string name="msg_ip_subkey_expired">Undernyckel gick ut %s</string>
<string name="msg_ip_subkey_expires">Undernyckel går ut %s</string>
@@ -685,7 +676,6 @@
<string name="msg_is_importing_subkeys">Bearbetar privata undernycklar</string>
<string name="msg_is_error_io_exc">Fel vid kodning av nyckelring</string>
<string name="msg_is_merge_public">Slår ihop importerade data med befintlig publik nyckelring</string>
- <string name="msg_is_merge_secret">Slår ihop importerade data med befintlig publik nyckelring</string>
<string name="msg_is_pubring_generate">Genererar publik nyckelring från privat nyckelring</string>
<string name="msg_is_subkey_nonexistent">Undernyckel %s inte tillgänglig i privat nyckelring</string>
<string name="msg_is_success_identical">Nyckelringen innehåller ingen ny information, inget att göra</string>
@@ -727,7 +717,6 @@
<string name="msg_cr">Genererar ny huvudnyckel</string>
<string name="msg_cr_error_no_user_id">Nyckelringar måste skapas med minst ett användar-ID!</string>
<string name="msg_cr_error_no_certify">Huvudnyckel måste ha en certifieringsflagga!</string>
- <string name="msg_cr_error_keysize_512">Nyckelstorlek måste vara större eller lika med 512!</string>
<string name="msg_cr_error_internal_pgp">Internt OpenPGP-fel!</string>
<string name="msg_cr_error_unknown_algo">Okänd algoritm vald. Detta är ett programmeringsfel, skicka en buggrapport!</string>
<string name="msg_cr_error_flags_dsa">Dåliga nyckelflaggor valda, DSA kan inte användas för kryptering!</string>
@@ -792,6 +781,7 @@
<string name="msg_dc_clear_decompress">Packar upp komprimerad data</string>
<string name="msg_dc_clear_meta_file">Filnamn: %s</string>
<string name="msg_dc_clear_meta_mime">MIME-typ: %s</string>
+ <string name="msg_dc_clear_meta_size">Filstorlek: %s</string>
<string name="msg_dc_clear_signature_bad">Signaturkontroll INTE OK!</string>
<string name="msg_dc_clear_signature_check">Verifierar signaturdata</string>
<string name="msg_dc_clear_signature_ok">Signaturkontroll OK</string>
@@ -806,6 +796,7 @@
<string name="msg_dc_sym">Hittade block med symmetriskt krypterad data</string>
<string name="msg_dc_unlocking">Låser upp privat nyckel</string>
<!--Messages for VerifySignedLiteralData operation-->
+ <string name="msg_vl_clear_meta_file">Filnamn: %s</string>
<!--Messages for SignEncrypt operation-->
<string name="msg_se_success">Signering/kryptering lyckades!</string>
<!--Messages for PgpSignEncrypt operation-->
@@ -833,22 +824,10 @@
<string name="msg_import_fetch_keyserver">Hämtar från nyckelserver: %s</string>
<string name="msg_import_fetch_keyserver_ok">Nyckelhämtning lyckades</string>
<string name="msg_import_keyserver">Använder nyckelserver %s</string>
- <string name="msg_import_fingerprint_ok">Kontroll av fingeravtyck OK</string>
<string name="msg_import_merge">Slår ihop data som tagits emot</string>
<string name="msg_import_error">Importoperation misslyckades!</string>
<string name="msg_import_partial">Importoperation lyckades, med fel!</string>
<string name="msg_import_success">Importoperation lyckades!</string>
- <plurals name="msg_export">
- <item quantity="one">Exporterar en nyckel</item>
- <item quantity="other">Exporterar %d nycklar</item>
- </plurals>
- <string name="msg_export_all">Exporterar alla nycklar</string>
- <string name="msg_export_public">Exporterar publik nyckel %s</string>
- <string name="msg_export_secret">Exporterar privat nyckel %s</string>
- <string name="msg_export_error_fopen">Fel vid öppning av fil!</string>
- <string name="msg_export_error_no_uri">Ingen URI specifierad!</string>
- <string name="msg_export_error_db">Databasfel!</string>
- <string name="msg_export_success">Exportoperation lyckades</string>
<string name="msg_del_error_empty">Inget att radera!</string>
<string name="msg_del_error_multi_secret">Privata nycklar kan bara raderas var för sig!</string>
<plurals name="msg_del">
@@ -865,6 +844,7 @@
<item quantity="one">Misslyckades med att radera en nyckel</item>
<item quantity="other">Misslyckades med att radera %d nycklar</item>
</plurals>
+ <!--Linked Identity verification-->
<string name="msg_acc_saved">Konto sparat</string>
<string name="msg_download_success">Hämtning lyckades!</string>
<string name="msg_download_no_valid_keys">Inga giltiga nycklar hittades i fil/urklipp!</string>
@@ -873,7 +853,7 @@
<item quantity="other">delar av den inlästa filen är giltiga OpenPGP-objekt men inte OpenPGP-nycklar</item>
</plurals>
<!--Messages for Keybase Verification operation-->
- <!--Messages for Export Log operation-->
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<!--Keyserver sync-->
<!--First Time-->
@@ -885,7 +865,6 @@
<!--unsorted-->
<string name="section_cert">Certifikatinformation</string>
<string name="label_user_id">Identitet</string>
- <string name="unknown_uid">&lt;okänd&gt;</string>
<string name="empty_certs">Inga certifikat för den här nyckeln</string>
<string name="section_uids_to_certify">Identiteter för</string>
<string name="label_revocation">Anledning till återkallelse</string>
@@ -920,4 +899,14 @@
<string name="no_nfc_support">Denna enhet stöder inte NFC</string>
<string name="unlocked">Upplåst</string>
<string name="nfc_settings">Inställningar</string>
+ <string name="error_nfc_unknown">Okänt fel</string>
+ <string name="error_nfc_try_again">Försök igen</string>
+ <string name="btn_delete_original">Radera ursprunglig fil</string>
+ <string name="view_internal">Visa i OpenKeychain</string>
+ <string name="error_clipboard_empty">Urklipp är tomt!</string>
+ <!--Other Linked Identity strings-->
+ <string name="linked_title_github">GitHub</string>
+ <string name="linked_title_twitter">Twitter</string>
+ <string name="linked_button_verify">Verifiera</string>
+ <string name="linked_text_confirming">Bekräftar…</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values-tr/strings.xml b/OpenKeychain/src/main/res/values-tr/strings.xml
index 090356f9d..e1644778c 100644
--- a/OpenKeychain/src/main/res/values-tr/strings.xml
+++ b/OpenKeychain/src/main/res/values-tr/strings.xml
@@ -23,7 +23,6 @@
<!--section-->
<string name="section_user_ids">Kimlikler</string>
<string name="section_keys">Alt anahtarlar</string>
- <string name="section_cloud_search">Bulut araması</string>
<string name="section_actions">Eylemler</string>
<string name="section_share_key">Anahtar</string>
<string name="section_key_server">Anahtar Sunucusu</string>
@@ -60,9 +59,7 @@
<string name="label_file_ascii_armor">ASCII formatında çıktıları etkinleştir</string>
<string name="label_write_version_header">Diğerlerinin OpenKeychain kullandığını bilmesine izin ver</string>
<string name="label_write_version_header_summary">OpenPGP imzalarına, şifrelenmiş metinlere ve dışa aktarılmış anahtarlara \'OpenKeychain v2.7\' yazar</string>
- <string name="label_use_default_yubikey_pin">Varsayılan YubiKey PIN\'ini kullan</string>
<string name="label_use_num_keypad_for_yubikey_pin">YubiKey PIN\'i için sayısal klavyeyi kullan</string>
- <string name="label_label_use_default_yubikey_pin_summary">NFC üzerinden YubiKey\'e ulaşmak için varsayılan PIN\'i (123456) kullanır</string>
<string name="label_to">Şuna şifrele:</string>
<string name="label_delete_after_decryption">Şifre çözme sonrasında sil</string>
<string name="label_encryption_algorithm">Şifreleme algoritması</string>
@@ -78,7 +75,6 @@
<string name="label_name">İsim</string>
<string name="label_comment">Yorum</string>
<string name="label_email">Eposta</string>
- <string name="label_send_key">Bulut ile eşitle</string>
<string name="label_fingerprint">Parmak izi</string>
<string name="expiry_date_dialog_title">Zaman aşımı tarihini ayarla</string>
<string name="label_preferred">tercih edilen</string>
@@ -88,8 +84,6 @@
<!--OrbotHelper strings-->
<!--InstallDialogFragment strings-->
<!--StartOrbotDialogFragment strings-->
- <string name="user_id_no_name">&lt;isimsiz&gt;</string>
- <string name="none">&lt;hiçbiri&gt;</string>
<plurals name="n_keys">
<item quantity="one">1 anahtar</item>
<item quantity="other">%d anahtar</item>
@@ -128,7 +122,6 @@
<string name="flag_authenticate">Kimlik kanıtlama</string>
<!--sentences-->
<string name="no_filemanager_installed">Uyumlu dosya yöneticisi yüklenmedi.</string>
- <string name="passphrase_for_symmetric_encryption">Simetrik şifreleme.</string>
<string name="encrypt_sign_successful">Başarıyla imzalandı ve/veya şifrelendi.</string>
<string name="encrypt_sign_clipboard_successful">Kopyalama önbelleğine başarıyla imzalandı ve/veya şifrelendi.</string>
<string name="select_encryption_key">En az bir şifreleme anahtarı seçiniz.</string>
@@ -147,7 +140,6 @@
<string name="nfc_successful">Anahtar NFC Beam ile başarıyla gönderildi!</string>
<string name="key_copied_to_clipboard">Anahtar kopyalama önbelleğine kopyalandı!</string>
<string name="fingerprint_copied_to_clipboard">Parmak izi kopyalama önbelleğine kopyalandı!</string>
- <string name="key_too_big_for_sharing">Anahtar bu yolla paylaşılamayacak kadar büyük!</string>
<string name="text_copied_to_clipboard">Metin kopyalama önbelleğine kopyalandı!</string>
<!--errors
no punctuation, all lowercase,
@@ -211,8 +203,8 @@
<string name="progress_encrypting">veri şifreleniyor...</string>
<string name="progress_decrypting">veri şifresi çözülüyor...</string>
<string name="progress_preparing_signature">imza hazırlanıyor...</string>
- <string name="progress_generating_signature">imza oluşturuluyor...</string>
<string name="progress_processing_signature">imza işleniyor...</string>
+ <string name="progress_generating_signature">imza oluşturuluyor...</string>
<string name="progress_verifying_signature">imza doğrulanıyor...</string>
<string name="progress_signing">imzalanıyor...</string>
<string name="progress_certifying">tasdikleniyor...</string>
@@ -226,10 +218,6 @@
<string name="progress_con_reimport">birleştir: yeniden içe aktarılıyor...</string>
<!--action strings-->
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -258,7 +246,6 @@
<string name="help_about_version">Sürüm:</string>
<!--Import-->
<string name="import_tab_keyserver">Anahtar Sunucusu</string>
- <string name="import_tab_cloud">Bulutta Ara</string>
<string name="import_tab_direct">Dosya/Kopyalama önbelleği</string>
<string name="import_tab_qr_code">QR Kodu/NFC</string>
<string name="import_import">Seçili anahtarları içe aktar</string>
@@ -269,10 +256,6 @@
<string name="with_warnings">, uyarılarla</string>
<string name="with_cancelled">, iptal edilene kadar</string>
<!--Import result toast-->
- <plurals name="import_keys_added_and_updated_1">
- <item quantity="one">Anahtar başarıyla içe aktarıldı</item>
- <item quantity="other">%1$d anahtar başarıyla içe aktarıldı</item>
- </plurals>
<plurals name="import_keys_with_errors">
<item quantity="one">Bir anahtar için alma başarısız.</item>
<item quantity="other">%d anahtar için içe aktarma başarısız!</item>
@@ -317,7 +300,6 @@
<item quantity="other">%d anahtar seçildi.</item>
</plurals>
<string name="key_list_filter_show_all">Tüm anahtarları göster</string>
- <string name="key_list_filter_show_certified">Sadece sertifikalı anahtarları göster</string>
<!--Key view-->
<string name="key_view_action_edit">Anahtarı düzenle</string>
<string name="key_view_action_encrypt">Metni şifrele</string>
@@ -332,10 +314,6 @@
<string name="key_view_tab_certs">Sertifikalar</string>
<string name="user_id_info_revoked_title">Yürürlükten kaldırılmış</string>
<string name="user_id_info_revoked_text">Bu kimlik anahtar sahibi tarafından yürürlükten kaldırılmış. Artık geçerli değil.</string>
- <string name="user_id_info_certified_title">Tasdiklenmiş</string>
- <string name="user_id_info_certified_text">Bu kimlik sizin tarafınızdan tasdiklendi.</string>
- <string name="user_id_info_uncertified_title">Tasdiklenmemiş</string>
- <string name="user_id_info_uncertified_text">Bu kimlik henüz tasdiklenmemiş. Bu kimliğin belirli bir kişiye ait olduğundan emin olamazsınız.</string>
<string name="user_id_info_invalid_title">Geçersiz</string>
<string name="user_id_info_invalid_text">Bu kimlikle ilgili yanlış olan bazı şeyler var!</string>
<!--Key trust-->
@@ -408,17 +386,12 @@
<!--Messages for PgpSignEncrypt operation-->
<string name="msg_crt_warn_not_found">Anahtar bulunamadı!</string>
<string name="msg_import_keyserver">%s anahtar sunucusu kullanılıyor</string>
- <string name="msg_import_fingerprint_ok">Parmakizi kontrolü TAMAM</string>
- <string name="msg_export_all">Tüm anahtarları dışa aktarma</string>
- <string name="msg_export_error_uri_open">URI akışı açılırken hata!</string>
- <string name="msg_export_error_db">Veritabanı hatası!</string>
- <string name="msg_export_error_io">Giriş/çıkış hatası!</string>
- <string name="msg_export_success">Dışa aktarma işlemi başarılı</string>
<string name="msg_del_error_empty">Silinecek bir şey yok!</string>
+ <!--Linked Identity verification-->
<string name="msg_acc_saved">Hesap kaydedildi</string>
<string name="msg_download_success">Başarıyla indirildi!</string>
<!--Messages for Keybase Verification operation-->
- <!--Messages for Export Log operation-->
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<!--Keyserver sync-->
<!--First Time-->
@@ -427,7 +400,6 @@
<!--unsorted-->
<string name="section_cert">Sertifika Detayları</string>
<string name="label_user_id">Kimlik</string>
- <string name="unknown_uid">&lt;bilinmeyen&gt;</string>
<string name="empty_certs">Bu anahtar için sertifika yok</string>
<string name="label_revocation">Yürürlükten Kaldırma Nedeni</string>
<string name="label_cert_type">Tip</string>
@@ -450,4 +422,5 @@
<!--TODO: rename all the things!-->
<!--<string name="enter_passphrase_twice">Enter password twice</string>-->
<!--<string name="nfc_text">Please place a NFC tag near your device</string>-->
+ <!--Other Linked Identity strings-->
</resources>
diff --git a/OpenKeychain/src/main/res/values-uk/strings.xml b/OpenKeychain/src/main/res/values-uk/strings.xml
index 6c0420c0b..1d9a02c06 100644
--- a/OpenKeychain/src/main/res/values-uk/strings.xml
+++ b/OpenKeychain/src/main/res/values-uk/strings.xml
@@ -23,7 +23,6 @@
<!--section-->
<string name="section_user_ids">Сутності</string>
<string name="section_keys">Підключі</string>
- <string name="section_cloud_search">Хмарний пошук</string>
<string name="section_actions">Дії</string>
<string name="section_share_key">Ключ</string>
<string name="section_key_server">Сервер ключів</string>
@@ -60,9 +59,7 @@
<string name="label_file_ascii_armor">Увімкнути ASCII Armor</string>
<string name="label_write_version_header">Нехай інші дізнаються, що ви користуєтеся OpenKeychain</string>
<string name="label_write_version_header_summary">Напишіть \'OpenKeychain v2.7\' для підписів, зашифрованого тексту та експортованих ключів OpenPGP</string>
- <string name="label_use_default_yubikey_pin">Вживати типовий YubiKey PIN</string>
<string name="label_use_num_keypad_for_yubikey_pin">Вживати цифрову клавіатуру для YubiKey PIN</string>
- <string name="label_label_use_default_yubikey_pin_summary">Вживається типовий PIN (123456) для доступу до YubiKey чреез NFC</string>
<string name="label_to">Зашифрувати до:</string>
<string name="label_delete_after_decryption">Вилучити після розшифрування</string>
<string name="label_encryption_algorithm">Алгоритм шифрування</string>
@@ -78,7 +75,6 @@
<string name="label_name">Назва</string>
<string name="label_comment">Коментар</string>
<string name="label_email">Ел. пошта</string>
- <string name="label_send_key">Синхронізувати із хмарою</string>
<string name="label_fingerprint">Відбиток</string>
<string name="expiry_date_dialog_title">Задати термін дії</string>
<string name="label_preferred">бажаний</string>
@@ -88,8 +84,6 @@
<!--OrbotHelper strings-->
<!--InstallDialogFragment strings-->
<!--StartOrbotDialogFragment strings-->
- <string name="user_id_no_name">&lt;без імені&gt;</string>
- <string name="none">&lt;жоден&gt;</string>
<plurals name="n_keys">
<item quantity="one">1 ключ</item>
<item quantity="few">%d ключі</item>
@@ -130,7 +124,6 @@
<string name="flag_authenticate">Перевірити справжність</string>
<!--sentences-->
<string name="no_filemanager_installed">Нема встановленого сумісного менеджера файлів.</string>
- <string name="passphrase_for_symmetric_encryption">Симетричне шифрування.</string>
<string name="encrypt_sign_successful">Успішно підписано та/або перевірено.</string>
<string name="encrypt_sign_clipboard_successful">Успішно підписано та/або зашифровано до буфера обміну.</string>
<string name="select_encryption_key">Виберіть принаймні один ключ шифрування.</string>
@@ -152,7 +145,6 @@
<string name="nfc_successful">Успішно надіслано ключ через промінь NFC!</string>
<string name="key_copied_to_clipboard">Ключ вже скопійовано у буфер обміну!</string>
<string name="fingerprint_copied_to_clipboard">Відбиток вже скопійовано до буфера обміну!</string>
- <string name="key_too_big_for_sharing">Ключ надто великий для цього способу поширення!</string>
<string name="text_copied_to_clipboard">Текст вже скопійовано у буфер обміну!</string>
<!--errors
no punctuation, all lowercase,
@@ -212,8 +204,8 @@
<string name="progress_encrypting">шифруються дані…</string>
<string name="progress_decrypting">розшифровуються дані…</string>
<string name="progress_preparing_signature">підготовка підпису…</string>
- <string name="progress_generating_signature">генерується підпис…</string>
<string name="progress_processing_signature">обробляється підпис…</string>
+ <string name="progress_generating_signature">генерується підпис…</string>
<string name="progress_verifying_signature">перевірка підпису…</string>
<string name="progress_signing">підписання…</string>
<string name="progress_certifying">сертифікується…</string>
@@ -227,10 +219,6 @@
<string name="progress_con_reimport">consolidate: повторний імпорт…</string>
<!--action strings-->
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -266,16 +254,6 @@
<!--Import from URL-->
<!--Generic result toast-->
<!--Import result toast-->
- <plurals name="import_keys_added_and_updated_1">
- <item quantity="one">Успішно імпортовано ключ.</item>
- <item quantity="few">Успішно імпортовано %1$d ключі.</item>
- <item quantity="other">Успішно імпортовано %1$d ключів.</item>
- </plurals>
- <plurals name="import_keys_added_and_updated_2">
- <item quantity="one">та оновлено ключ%2$s.</item>
- <item quantity="few">та оновлено %1$d ключі%2$s.</item>
- <item quantity="other">та оновлено %1$d ключів%2$s.</item>
- </plurals>
<plurals name="import_keys_added">
<item quantity="one">Успішно імпортований ключ%2$s.</item>
<item quantity="few">Успішно імпортовано %1$d ключі%2$s.</item>
@@ -343,8 +321,6 @@
<string name="key_view_tab_certs">Сертифікати</string>
<string name="user_id_info_revoked_title">Відхилено</string>
<string name="user_id_info_revoked_text">Ця сутність вже відкликана власником ключа. Вона більше не дійсна.</string>
- <string name="user_id_info_certified_title">Сертифіковано</string>
- <string name="user_id_info_uncertified_title">Несертифіковано</string>
<string name="user_id_info_invalid_title">Недійсна</string>
<string name="user_id_info_invalid_text">Щось неправильне у цій сутності!</string>
<!--Key trust-->
@@ -454,7 +430,6 @@
<string name="msg_cr">Генерується новий основний ключ</string>
<string name="msg_cr_error_no_master">Не вказано параметрів основного ключа!</string>
<string name="msg_cr_error_no_certify">Основний ключ повинен мати прапорець certify!</string>
- <string name="msg_cr_error_keysize_512">Розмір ключа має бути більшим або рівним 512!</string>
<!--modifySecretKeyRing-->
<string name="msg_mr">Змінюється в\'язка %s</string>
<string name="msg_mf_error_encode">Виняток шифрування!</string>
@@ -501,13 +476,14 @@
<!--Messages for VerifySignedLiteralData operation-->
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Linked Identity verification-->
<plurals name="error_import_non_pgp_part">
<item quantity="one">частина завантаженого файлу є вірним об\'єктом OpenPGP, але не ключем OpenPGP</item>
<item quantity="few">частини завантаженого файлу є вірним об\'єктом OpenPGP, але не ключем OpenPGP</item>
<item quantity="other">частин завантаженого файлу є вірним об\'єктом OpenPGP, але не ключем OpenPGP</item>
</plurals>
<!--Messages for Keybase Verification operation-->
- <!--Messages for Export Log operation-->
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<!--Keyserver sync-->
<!--First Time-->
@@ -517,7 +493,6 @@
<string name="section_certifier_id">Ким підписаний</string>
<string name="section_cert">Дані сертифікату</string>
<string name="label_user_id">Сутність</string>
- <string name="unknown_uid">&lt;невідомо&gt;</string>
<string name="empty_certs">Немає сертифікатів для цього ключа</string>
<string name="label_revocation">Причина відхилення</string>
<string name="label_cert_type">Тип</string>
@@ -535,4 +510,5 @@
<!--TODO: rename all the things!-->
<!--<string name="enter_passphrase_twice">Enter password twice</string>-->
<!--<string name="nfc_text">Please place a NFC tag near your device</string>-->
+ <!--Other Linked Identity strings-->
</resources>
diff --git a/OpenKeychain/src/main/res/values-v23/themes.xml b/OpenKeychain/src/main/res/values-v23/themes.xml
new file mode 100644
index 000000000..29bd762c0
--- /dev/null
+++ b/OpenKeychain/src/main/res/values-v23/themes.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- see http://stackoverflow.com/questions/32169303/activity-did-not-call-finish-api-23 -->
+ <style name="Theme.Keychain.Transparent" parent="@android:style/Theme.Translucent.NoTitleBar" />
+
+</resources>
diff --git a/OpenKeychain/src/main/res/values-zh-rTW/strings.xml b/OpenKeychain/src/main/res/values-zh-rTW/strings.xml
index 74d1cd781..bc9f08a5e 100644
--- a/OpenKeychain/src/main/res/values-zh-rTW/strings.xml
+++ b/OpenKeychain/src/main/res/values-zh-rTW/strings.xml
@@ -31,7 +31,6 @@
<string name="title_exchange_keys">交換金鑰</string>
<string name="title_advanced_key_info">延伸資訊</string>
<string name="title_delete_secret_key">刪除您的金鑰 \'%s\'?</string>
- <string name="title_export_log">匯出記錄</string>
<string name="title_manage_my_keys">管理我的金鑰</string>
<!--section-->
<string name="section_user_ids">身份</string>
@@ -39,9 +38,6 @@
<string name="section_linked_system_contact">已關聯帳戶</string>
<string name="section_should_you_trust">您信任這把金鑰嗎?</string>
<string name="section_keys">子金鑰</string>
- <string name="section_cloud_search">雲端查詢</string>
- <string name="section_passphrase_cache">金鑰密碼快取</string>
- <string name="section_proxy_settings">代理伺服器設定</string>
<string name="section_certify">確認</string>
<string name="section_actions">操作</string>
<string name="section_share_key">金鑰</string>
@@ -67,12 +63,9 @@
<string name="btn_back">返回</string>
<string name="btn_no">不</string>
<string name="btn_match">指紋相符</string>
- <string name="btn_share_encrypted_signed">加密並分享文字</string>
- <string name="btn_copy_encrypted_signed">加密並複製文字</string>
<string name="btn_view_cert_key">檢視簽署的金鑰</string>
<string name="btn_create_key">建立金鑰</string>
<string name="btn_add_files">加入檔案</string>
- <string name="btn_share_decrypted_text">分享已解密的訊息</string>
<string name="btn_copy_decrypted_text">複製已解密的訊息</string>
<string name="btn_decrypt_clipboard">從剪貼簿中讀取</string>
<string name="btn_decrypt_files">選擇要解密的檔案</string>
@@ -86,7 +79,6 @@
<!--menu-->
<string name="menu_preferences">設定</string>
<string name="menu_help">說明</string>
- <string name="menu_export_key">匯出到檔案</string>
<string name="menu_delete_key">刪除金鑰</string>
<string name="menu_manage_keys">管理我的金鑰</string>
<string name="menu_search">搜尋</string>
@@ -97,8 +89,6 @@
<string name="menu_export_all_keys">匯出所有金鑰</string>
<string name="menu_update_all_keys">更新所有金鑰</string>
<string name="menu_advanced">附加訊息</string>
- <string name="menu_certify_fingerprint">藉由指紋比對來認證</string>
- <string name="menu_export_log">匯出記錄</string>
<string name="menu_keyserver_add">新增</string>
<!--label-->
<string name="label_message">文字</string>
@@ -114,9 +104,7 @@
<string name="label_file_ascii_armor">以ASCII輸出</string>
<string name="label_write_version_header">讓別人知道我在使用OpenKeychain</string>
<string name="label_write_version_header_summary">在簽名、密文與匯出的金鑰裡寫入\'OpenKeychain v2.7\'</string>
- <string name="label_use_default_yubikey_pin">使用預設的 Yubikey PIN</string>
<string name="label_use_num_keypad_for_yubikey_pin">輸入 YubiKey PIN 時使用數字鍵盤</string>
- <string name="label_label_use_default_yubikey_pin_summary">使用預設的 PIN (123456) 來使用 NFC 存取 Yubikeys</string>
<string name="label_asymmetric_from">簽名:</string>
<string name="label_to">加密給:</string>
<string name="label_delete_after_encryption">加密後刪除檔案</string>
@@ -139,7 +127,6 @@
<string name="label_name">名字</string>
<string name="label_comment">註記</string>
<string name="label_email">電子郵件</string>
- <string name="label_send_key">與雲端同步</string>
<string name="label_fingerprint">指紋</string>
<string name="expiry_date_dialog_title">設定有效期限</string>
<string name="label_keyservers_title">金鑰伺服器</string>
@@ -149,8 +136,6 @@
<string name="label_enable_compression">啓用壓縮</string>
<string name="label_encrypt_filenames">加密檔名</string>
<string name="label_hidden_recipients">隱藏收件人</string>
- <string name="label_verify_keyserver">驗證金鑰伺服器</string>
- <string name="label_enter_keyserver_url">輸入金鑰伺服器網址</string>
<string name="label_keyserver_dialog_delete">刪除金鑰伺服器</string>
<string name="label_theme">主題</string>
<string name="pref_keyserver">OpenPGP金鑰伺服器</string>
@@ -171,22 +156,16 @@
<string name="pref_proxy_type_choice_http">HTTP</string>
<string name="pref_proxy_type_choice_socks">SOCKS</string>
<!--OrbotHelper strings-->
- <string name="orbot_ignore_tor">不使用Tor</string>
<!--InstallDialogFragment strings-->
<string name="orbot_install_dialog_title">是否安裝Orbot以使用Tor?</string>
<string name="orbot_install_dialog_install">安裝</string>
<string name="orbot_install_dialog_content">您必須安裝Orbot並透過它進行網路代理。您是否要安裝Orbot?</string>
<string name="orbot_install_dialog_cancel">取消</string>
- <string name="orbot_install_dialog_ignore_tor">不使用Tor</string>
<!--StartOrbotDialogFragment strings-->
<string name="orbot_start_dialog_title">啟動Orbot?</string>
- <string name="orbot_start_dialog_content">Orbot尚未執行,您希望啟動它並連結到Tor嗎?</string>
<string name="orbot_start_btn">啟動Orbot</string>
<string name="orbot_start_dialog_start">啟動Orbot</string>
<string name="orbot_start_dialog_cancel">取消</string>
- <string name="orbot_start_dialog_ignore_tor">不使用Tor</string>
- <string name="user_id_no_name">&lt;無名&gt;</string>
- <string name="none">&lt;無&gt;</string>
<plurals name="n_keys">
<item quantity="other">%d 金鑰</item>
</plurals>
@@ -228,7 +207,6 @@
<string name="no_filemanager_installed">找不到相容的檔案管理員。</string>
<string name="passphrases_do_not_match">密碼不相符。</string>
<string name="passphrase_must_not_be_empty">請輸入密碼。</string>
- <string name="passphrase_for_symmetric_encryption">對稱加密。</string>
<string name="passphrase_for">輸入 %s 的密碼</string>
<string name="pin_for">輸入 \'%s\' 的 PIN</string>
<string name="yubikey_pin_for">輸入 PIN 來存取 \'%s\' 的 YubiKey</string>
@@ -247,7 +225,6 @@
<string name="specify_backup_dest_secret_single">將匯出公鑰及私鑰,請選擇輸出檔案位置。\n注意:已經存在的檔案將被覆蓋。</string>
<string name="specify_backup_dest_secret">將匯出所有金鑰,包含您自己的公鑰及私鑰,請選擇輸出檔案位置。\n注意:已經存在的檔案將被覆蓋。</string>
<string name="key_deletion_confirmation_multi">您真的想要刪除所有已選金鑰嗎?</string>
- <string name="secret_key_deletion_confirmation">刪除之後您將無法閱讀以這把金鑰加密的訊息,而且所有用這把金鑰做的認證都會失效!</string>
<string name="public_key_deletetion_confirmation">刪除金鑰 \'%s\' ?</string>
<string name="also_export_secret_keys">一併匯出私鑰</string>
<string name="reinstall_openkeychain">您遇到了一個已知的 Android 錯誤。如果您想要鏈接聯絡人和金鑰,請重新安裝 OpenKeychain。</string>
@@ -256,7 +233,6 @@
<string name="no_keys_exported">沒有金鑰被匯出。</string>
<string name="key_creation_el_gamal_info">注意:只有子金鑰支援 ElGamal。</string>
<string name="key_not_found">無法找到金鑰 %08X。</string>
- <string name="specify_file_to_export_log_to">請指定欲匯出的檔案。\n警告:已經存在的檔案將被覆蓋。</string>
<plurals name="bad_keys_encountered">
<item quantity="other">%d 忽略不良的密鑰。或許您在輸出時使用\n --export-secret-subkeys 選項\n 請確認您使用\n --export-secret-keys\n 作爲選項。\"</item>
</plurals>
@@ -265,7 +241,6 @@
<string name="key_copied_to_clipboard">金鑰已複製到剪貼簿!</string>
<string name="fingerprint_copied_to_clipboard">指紋已複製到剪貼簿!</string>
<string name="select_key_to_certify">請選擇一把金鑰來做認證 !</string>
- <string name="key_too_big_for_sharing">金鑰太大無法使用此方式分享!</string>
<string name="text_copied_to_clipboard">文字已複製到剪貼簿!</string>
<!--errors
no punctuation, all lowercase,
@@ -351,8 +326,8 @@
<string name="progress_encrypting">正在加密資料…</string>
<string name="progress_decrypting">正在解密資料…</string>
<string name="progress_preparing_signature">正在準備簽名…</string>
- <string name="progress_generating_signature">正在產生簽名…</string>
<string name="progress_processing_signature">正在處理簽名…</string>
+ <string name="progress_generating_signature">正在產生簽名…</string>
<string name="progress_verifying_signature">正在驗證簽名…</string>
<string name="progress_signing">簽名中…</string>
<string name="progress_certifying">正在認證…</string>
@@ -362,15 +337,10 @@
<string name="progress_verifying_integrity">正在驗證完整性…</string>
<string name="progress_deleting_securely">正在安全地刪除 \'%s\'...</string>
<string name="progress_deleting">正在刪除金鑰…</string>
- <string name="progress_verifying_keyserver_url">正在驗證金鑰伺服器...</string>
<string name="progress_starting_orbot">正在啟動Orbot...</string>
<!--action strings-->
<string name="hint_cloud_search_hint">使用姓名,電子郵件尋找...</string>
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_768">768</string>
- <string name="key_size_1024">1024</string>
- <string name="key_size_1536">1536</string>
<string name="key_size_2048">2048</string>
<string name="key_size_3072">3072</string>
<string name="key_size_4096">4096</string>
@@ -400,7 +370,6 @@
<string name="help_about_version">版本:</string>
<!--Import-->
<string name="import_tab_keyserver">金鑰伺服器</string>
- <string name="import_tab_cloud">雲端查詢</string>
<string name="import_tab_direct">檔案/剪貼簿</string>
<string name="import_tab_qr_code">二維條碼/NFC</string>
<string name="import_import">匯入選擇的金鑰</string>
@@ -415,12 +384,6 @@
<string name="with_warnings">,包含警告</string>
<string name="with_cancelled">,直到被取消</string>
<!--Import result toast-->
- <plurals name="import_keys_added_and_updated_1">
- <item quantity="other">成功匯入%1$d金鑰</item>
- </plurals>
- <plurals name="import_keys_added_and_updated_2">
- <item quantity="other">並更新%1$d金鑰%2$s。</item>
- </plurals>
<plurals name="import_keys_added">
<item quantity="other">成功匯入%1$d金鑰%2$s。</item>
</plurals>
@@ -456,9 +419,6 @@
<string name="revoke_nothing">沒有任何金鑰被撤銷。</string>
<string name="revoke_cancelled">撤銷動作被取消。</string>
<!--Certify result toast-->
- <plurals name="certify_keys_ok">
- <item quantity="other">成功認證 %1$d 金鑰%2$s。</item>
- </plurals>
<plurals name="certify_keys_with_errors">
<item quantity="other">認證 %d 金鑰失敗 !</item>
</plurals>
@@ -531,23 +491,11 @@
<string name="key_view_tab_keybase">Keybase.io</string>
<string name="user_id_info_revoked_title">已撤銷</string>
<string name="user_id_info_revoked_text">這個身分識別被金鑰持有人撤銷,已不再有效。</string>
- <string name="user_id_info_certified_title">已認證</string>
- <string name="user_id_info_certified_text">這個身分識別已經過你的認證。</string>
- <string name="user_id_info_uncertified_title">未認證</string>
- <string name="user_id_info_uncertified_text">這個身分識別尚未經過認證,你不能確認這個身分識別是否屬於真的某個人。</string>
<string name="user_id_info_invalid_title">無效</string>
<string name="user_id_info_invalid_text">這個身份有些錯誤!</string>
<!--Key trust-->
- <string name="key_trust_already_verified">您已經確認這把金鑰!</string>
- <string name="key_trust_it_is_yours">這把是您的金鑰!</string>
- <string name="key_trust_maybe">這把金鑰未被撤銷且尚未過期。\n金鑰尚未進行確認,但你可以選擇信任它。</string>
- <string name="key_trust_revoked">這把金鑰已被持有者撤銷。您不應該信任它。</string>
- <string name="key_trust_expired">這把金鑰已經過期。您不應該信任它。</string>
- <string name="key_trust_old_keys">用來解密在金鑰失效前加密的訊息還勉強可以接受。</string>
- <string name="key_trust_no_cloud_evidence">雲端上沒有證據能證明這把金鑰的可信度。</string>
<string name="key_trust_start_cloud_search">開始搜尋</string>
<string name="key_trust_results_prefix">Keybase.io提供“證據”證明這把金鑰的持有人:</string>
- <string name="key_trust_header_text">注意:Keybase.io證據是個OpenKeychain實驗性功能。我們推薦你另外以QR條碼或是NFC交換金鑰進行確認。</string>
<!--keybase proof stuff-->
<string name="keybase_narrative_twitter">用下列身分在Twitter參與討論:%s</string>
<string name="keybase_proof_failure">很不幸地我們沒法驗證這些證據。</string>
@@ -591,7 +539,6 @@
<string name="edit_key_error_bad_nfc_size">智慧卡不支援該金鑰長度!</string>
<string name="edit_key_error_bad_nfc_stripped">無法移動金鑰至智慧卡(已移動或被卸除)!</string>
<!--Create key-->
- <string name="create_key_upload">與雲端同步</string>
<string name="create_key_empty">必填欄位</string>
<string name="create_key_passphrases_not_equal">密碼不相符</string>
<string name="create_key_final_text">您輸入了以下資訊:</string>
@@ -607,12 +554,9 @@
<string name="create_key_add_email_text">附加的電子郵件同樣與您的金鑰有所關聯,可以提供您安全的通訊。</string>
<string name="create_key_email_already_exists_text">電子郵件地址已經存在</string>
<string name="create_key_email_invalid_email">電子郵件地址無效</string>
- <string name="create_key_yubi_key_pin_text">請記住您的PIN碼,等會兒您的YubiKey需要它。請紀錄下管理者PIN碼並且將它保存在安全的地方。</string>
<string name="create_key_yubi_key_pin">PIN碼</string>
<string name="create_key_yubi_key_admin_pin">管理者PIN碼</string>
- <string name="create_key_yubi_key_pin_repeat_text">請輸入PIN碼及管理者PIN碼以繼續執行。</string>
<string name="create_key_yubi_key_pin_repeat">重複PIN碼</string>
- <string name="create_key_yubi_key_admin_pin_repeat">重複管理者PIN碼</string>
<string name="create_key_yubi_key_pin_not_correct">PIN碼不正確!</string>
<!--View key-->
<string name="view_key_revoked">已撤銷:不該再使用此金鑰!</string>
@@ -625,10 +569,8 @@
<!--Add/Edit keyserver-->
<string name="add_keyserver_dialog_title">新增金鑰伺服器</string>
<string name="edit_keyserver_dialog_title">編輯金鑰伺服器</string>
- <string name="add_keyserver_verified">已驗證金鑰伺服器!</string>
<string name="add_keyserver_without_verification">已新增金鑰伺服器但並未進行驗證。</string>
<string name="add_keyserver_invalid_url">URL無效!</string>
- <string name="add_keyserver_connection_failed">連線到金鑰伺服器失敗。請確認金鑰伺服器網址及網路連線。</string>
<string name="keyserver_preference_deleted">已刪除 %s</string>
<string name="keyserver_preference_cannot_delete_last">無法刪除金鑰伺服器。請至少保留一個金鑰伺服器!</string>
<!--Navigation Drawer-->
@@ -638,7 +580,6 @@
<string name="drawer_open">開啟導航列</string>
<string name="drawer_close">關閉導航列</string>
<string name="my_keys">我的金鑰</string>
- <string name="nav_backup">備份</string>
<!--hints-->
<string name="encrypt_content_edit_text_hint">輸入文字</string>
<!--certs-->
@@ -681,7 +622,6 @@
<string name="msg_ip_master_flags_xxxa">主要標記:驗證</string>
<string name="msg_ip_master_flags_xxxx">主要標記:無</string>
<string name="msg_ip_merge_public">將匯入的資料合併至公鑰鑰匙圈</string>
- <string name="msg_ip_merge_secret">將匯入的資料合併至密鑰鑰匙圈</string>
<string name="msg_ip_subkey">正在處理子金鑰%s</string>
<string name="msg_ip_subkey_expired">子金鑰已於%s過期</string>
<string name="msg_ip_subkey_expires">子金鑰將於%s過期</string>
@@ -708,7 +648,6 @@
<!--Import Secret log entries-->
<string name="msg_is_db_exception">資料庫錯誤!</string>
<string name="msg_is_merge_public">將匯入的資料合併至公鑰鑰匙圈</string>
- <string name="msg_is_merge_secret">將匯入的資料合併至密鑰鑰匙圈</string>
<string name="msg_is_pubring_generate">從密鑰鑰匙圈產生公鑰鑰匙圈</string>
<string name="msg_is_success_identical">鑰匙圈沒有新資料,不必進行操作</string>
<string name="msg_is_success">成功匯入密鑰鑰匙圈</string>
@@ -737,19 +676,16 @@
<string name="msg_import_fetch_keyserver">從金鑰伺服器取回:%s</string>
<string name="msg_import_fetch_keyserver_ok">成功取得金鑰</string>
<string name="msg_import_keyserver">使用金鑰伺服器%s</string>
- <string name="msg_import_fingerprint_ok">指紋檢查正確</string>
<string name="msg_import_merge">正在合併取得的資料</string>
- <string name="msg_export_error_db">資料庫錯誤!</string>
- <string name="msg_export_error_io">輸入/輸出錯誤!</string>
- <string name="msg_export_success">匯出處理成功</string>
<string name="msg_del_error_empty">沒有東西可以刪除!</string>
<string name="msg_del_error_multi_secret">私鑰只能分別刪除!</string>
+ <!--Linked Identity verification-->
<string name="msg_acc_saved">帳戶已儲存</string>
<string name="msg_download_success">下載成功!</string>
<string name="msg_download_no_valid_keys">在檔案/剪貼簿中找不到有效的金鑰!</string>
<string name="msg_download_query_failed">查詢金鑰的時候發生錯誤。</string>
<!--Messages for Keybase Verification operation-->
- <!--Messages for Export Log operation-->
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<!--Keyserver sync-->
<!--First Time-->
@@ -758,7 +694,6 @@
<string name="first_time_yubikey">使用YubiKey NEO</string>
<string name="first_time_skip">跳過設置</string>
<!--unsorted-->
- <string name="unknown_uid">&lt;未知&gt;</string>
<string name="empty_certs">這把金鑰未經過認證</string>
<string name="certs_text">只有有效的自簽署認證以及經由你的金鑰簽署的有效認證會被顯示在這。</string>
<string name="label_revocation">撤銷原因</string>
@@ -784,4 +719,5 @@
<string name="nfc_write_succesful">成功寫入 NFC 標籤</string>
<string name="unlocked">解鎖</string>
<string name="nfc_settings">設定</string>
+ <!--Other Linked Identity strings-->
</resources>
diff --git a/OpenKeychain/src/main/res/values-zh/strings.xml b/OpenKeychain/src/main/res/values-zh/strings.xml
index ad85fd8ce..7046d5cd7 100644
--- a/OpenKeychain/src/main/res/values-zh/strings.xml
+++ b/OpenKeychain/src/main/res/values-zh/strings.xml
@@ -31,7 +31,6 @@
<string name="title_exchange_keys">交换密钥</string>
<string name="title_advanced_key_info">更多信息</string>
<string name="title_delete_secret_key">删除你的密钥 \'%s\' ?</string>
- <string name="title_export_log">导出日志</string>
<string name="title_manage_my_keys">管理我的密钥</string>
<!--section-->
<string name="section_user_ids">用户名</string>
@@ -39,11 +38,7 @@
<string name="section_linked_system_contact">关联系统联系人</string>
<string name="section_should_you_trust">应该相信此密钥?</string>
<string name="section_proof_details">验证</string>
- <string name="section_cloud_evidence">云端验证</string>
<string name="section_keys">子密钥</string>
- <string name="section_cloud_search">在线搜索</string>
- <string name="section_passphrase_cache">密码缓存</string>
- <string name="section_proxy_settings">代理服务器设置</string>
<string name="section_gui">界面</string>
<string name="section_certify">确认</string>
<string name="section_actions">动作</string>
@@ -70,12 +65,9 @@
<string name="btn_back">返回</string>
<string name="btn_no">否</string>
<string name="btn_match">密钥指纹符合</string>
- <string name="btn_share_encrypted_signed">加密并分享</string>
- <string name="btn_copy_encrypted_signed">加密并复制</string>
<string name="btn_view_cert_key">显示密钥</string>
<string name="btn_create_key">创建密钥</string>
<string name="btn_add_files">添加密钥</string>
- <string name="btn_share_decrypted_text">分享解密文本</string>
<string name="btn_copy_decrypted_text">复制解密文本</string>
<string name="btn_decrypt_clipboard">从剪贴板导入</string>
<string name="btn_decrypt_files">选择导入文件</string>
@@ -89,7 +81,6 @@
<!--menu-->
<string name="menu_preferences">参数设置</string>
<string name="menu_help">帮助</string>
- <string name="menu_export_key">导出到文件</string>
<string name="menu_delete_key">删除密钥</string>
<string name="menu_manage_keys">管理我的密钥</string>
<string name="menu_search">搜索</string>
@@ -100,8 +91,6 @@
<string name="menu_export_all_keys">导出全部密钥</string>
<string name="menu_update_all_keys">更新所有密钥</string>
<string name="menu_advanced">更多信息</string>
- <string name="menu_certify_fingerprint">通过密钥指纹比较确认</string>
- <string name="menu_export_log">导出日志</string>
<string name="menu_keyserver_add">添加</string>
<!--label-->
<string name="label_message">文本</string>
@@ -118,9 +107,7 @@
<string name="label_file_ascii_armor">启用ASCII文本化</string>
<string name="label_write_version_header">写入文件头信息</string>
<string name="label_write_version_header_summary">在OpenPGP签名、加密文本和导出密钥中写入 \'OpenKeychain v2.7\' 标记。</string>
- <string name="label_use_default_yubikey_pin">使用默认YubiKey PIN</string>
<string name="label_use_num_keypad_for_yubikey_pin">为YubiKey PIN使用数字键盘</string>
- <string name="label_label_use_default_yubikey_pin_summary">使用默认PIN (123456)访问YubiKeys</string>
<string name="label_message_compression">文本压缩</string>
<string name="label_file_compression">文件压缩</string>
<string name="label_keyservers">选择OpenPGP 密钥服务器</string>
@@ -188,7 +175,6 @@
<string name="no_filemanager_installed">安装了不匹配的文件管理器</string>
<string name="passphrases_do_not_match">密码不匹配</string>
<string name="passphrase_must_not_be_empty">请输入一个密码</string>
- <string name="passphrase_for_symmetric_encryption">对称加密</string>
<string name="encrypt_sign_successful">加密并签名成功</string>
<string name="encrypt_sign_clipboard_successful">加密签名并复制到剪贴板成功</string>
<string name="select_encryption_key">选择至少一个加密密钥</string>
@@ -205,7 +191,6 @@
<string name="key_copied_to_clipboard">复制密钥到剪贴板</string>
<string name="fingerprint_copied_to_clipboard">复制签名到剪贴板</string>
<string name="select_key_to_certify">选择验证密钥</string>
- <string name="key_too_big_for_sharing">密钥太长</string>
<string name="text_copied_to_clipboard">复制文本到剪贴板</string>
<!--errors
no punctuation, all lowercase,
@@ -233,8 +218,6 @@
<string name="progress_finding_key">正在查找密钥</string>
<!--action strings-->
<!--key bit length selections-->
- <string name="key_size_512">512</string>
- <string name="key_size_1024">1024</string>
<string name="key_size_2048">2048</string>
<string name="key_size_4096">4096</string>
<!--elliptic curve names-->
@@ -298,8 +281,9 @@
<!--Messages for VerifySignedLiteralData operation-->
<!--Messages for SignEncrypt operation-->
<!--Messages for PgpSignEncrypt operation-->
+ <!--Linked Identity verification-->
<!--Messages for Keybase Verification operation-->
- <!--Messages for Export Log operation-->
+ <!--Messages for Mime parsing operation-->
<!--PassphraseCache-->
<!--Keyserver sync-->
<!--First Time-->
@@ -309,4 +293,5 @@
<!--TODO: rename all the things!-->
<!--<string name="enter_passphrase_twice">Enter password twice</string>-->
<!--<string name="nfc_text">Please place a NFC tag near your device</string>-->
+ <!--Other Linked Identity strings-->
</resources>
diff --git a/OpenKeychain/src/main/res/values/arrays.xml b/OpenKeychain/src/main/res/values/arrays.xml
index 28b6fcd78..393a1e091 100644
--- a/OpenKeychain/src/main/res/values/arrays.xml
+++ b/OpenKeychain/src/main/res/values/arrays.xml
@@ -48,17 +48,15 @@
<item>@string/key_size_custom</item>
</string-array>
<string-array name="elgamal_key_size_spinner_values" translatable="false">
- <item>@string/key_size_1536</item>
<item>@string/key_size_2048</item>
<item>@string/key_size_3072</item>
<item>@string/key_size_4096</item>
<item>@string/key_size_8192</item>
</string-array>
<string-array name="dsa_key_size_spinner_values" translatable="false">
- <item>@string/key_size_512</item>
- <item>@string/key_size_768</item>
- <item>@string/key_size_1024</item>
- <item>@string/key_size_custom</item>
+ <item>@string/key_size_2048</item>
+ <item>@string/key_size_3072</item>
+ <item>@string/key_size_4096</item>
</string-array>
<string-array name="theme_entries" translatable="false">
diff --git a/OpenKeychain/src/main/res/values/colors.xml b/OpenKeychain/src/main/res/values/colors.xml
index 06fe2a9cd..4eb9e7d68 100644
--- a/OpenKeychain/src/main/res/values/colors.xml
+++ b/OpenKeychain/src/main/res/values/colors.xml
@@ -33,4 +33,7 @@
<color name="translucent_scrim_bottom">#2A000000</color>
<color name="translucent_scrim_bottom_center">#2A000000</color>
+ <!-- linked ID view -->
+ <color name="link_text_material_light">#ff009688</color>
+
</resources>
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 312bf4023..ff148b0c7 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -30,6 +30,7 @@
<string name="title_export_keys">"Backup Keys"</string>
<string name="title_key_not_found">"Key Not Found"</string>
<string name="title_send_key">"Upload to Keyserver"</string>
+ <string name="title_backup">"Backup Key"</string>
<string name="title_certify_key">"Confirm Key"</string>
<string name="title_key_details">"Key Details"</string>
<string name="title_help">"Help"</string>
@@ -62,6 +63,7 @@
<string name="section_share_key">"Key"</string>
<string name="section_key_server">"Keyserver"</string>
<string name="section_fingerprint">"Fingerprint"</string>
+ <string name="section_phrases">"Phrases"</string>
<string name="section_encrypt">"Encrypt"</string>
<string name="section_decrypt">"Decrypt / Verify"</string>
<string name="section_current_expiry">"Current expiry"</string>
@@ -83,12 +85,15 @@
<string name="btn_back">"Back"</string>
<string name="btn_no">"No"</string>
<string name="btn_match">"Fingerprints match"</string>
+ <string name="btn_match_phrases">"Phrases match"</string>
<string name="btn_share_encrypted_signed">"Encrypt/sign and share text"</string>
<string name="btn_copy_encrypted_signed">"Encrypt/sign and copy text"</string>
+ <string name="btn_paste_encrypted_signed">"Encrypt/sign and paste text"</string>
<string name="btn_view_cert_key">"View certification key"</string>
<string name="btn_create_key">"Create key"</string>
<string name="btn_add_files">"Add file(s)"</string>
<string name="btn_share_decrypted_text">"Share"</string>
+ <string name="btn_open_with">"Open with…"</string>
<string name="btn_copy_decrypted_text">"Copy decrypted text"</string>
<string name="btn_decrypt_clipboard">"Read from clipboard"</string>
<string name="btn_decrypt_files">"Select input file"</string>
@@ -99,6 +104,7 @@
<string name="btn_add_keyserver">"Add"</string>
<string name="btn_save_default">"Save as default"</string>
<string name="btn_saved">"Saved!"</string>
+ <string name="btn_not_matching">"Doesn't match"</string>
<!-- Content Description -->
<string name="cd_encrypt_files">"Encrypt Files"</string>
@@ -109,7 +115,7 @@
<!-- menu -->
<string name="menu_preferences">"Settings"</string>
<string name="menu_help">"Help"</string>
- <string name="menu_export_key">"Backup to file"</string>
+ <string name="menu_export_key">"Backup key"</string>
<string name="menu_delete_key">"Delete key"</string>
<string name="menu_manage_keys">"Manage my keys"</string>
<string name="menu_search">"Search"</string>
@@ -121,7 +127,7 @@
<string name="menu_update_all_keys">"Update all keys"</string>
<string name="menu_advanced">"Extended information"</string>
<string name="menu_certify_fingerprint">"Confirm via fingerprint"</string>
- <string name="menu_certify_fingerprint_word">"Confirm via words"</string>
+ <string name="menu_certify_fingerprint_phrases">"Confirm via phrases"</string>
<string name="menu_share_log">"Share Log"</string>
<string name="menu_keyserver_add">"Add"</string>
@@ -133,6 +139,7 @@
<string name="label_file_colon">"File:"</string>
<string name="label_no_passphrase">"No Password"</string>
<string name="label_passphrase">"Password"</string>
+ <string name="label_pin">"PIN"</string>
<string name="label_unlock">"Unlocking…"</string>
<string name="label_passphrase_again">"Repeat Password"</string>
<string name="label_show_passphrase">"Show Password"</string>
@@ -141,9 +148,7 @@
<string name="label_file_ascii_armor">"Enable ASCII Armor"</string>
<string name="label_write_version_header">"Let others know that you're using OpenKeychain"</string>
<string name="label_write_version_header_summary">"Writes 'OpenKeychain v2.7' to OpenPGP signatures, ciphertext, and exported keys"</string>
- <string name="label_use_default_yubikey_pin">"Use default YubiKey PIN"</string>
<string name="label_use_num_keypad_for_yubikey_pin">Use number keypad for YubiKey PIN</string>
- <string name="label_label_use_default_yubikey_pin_summary">"Uses default PIN (123456) to access YubiKeys over NFC"</string>
<string name="label_asymmetric_from">"Sign with:"</string>
<string name="label_to">"Encrypt to:"</string>
<string name="label_delete_after_encryption">"Delete files after encryption"</string>
@@ -178,8 +183,9 @@
<string name="label_encrypt_filenames">"Encrypt filenames"</string>
<string name="label_hidden_recipients">"Hide recipients"</string>
- <string name="label_verify_keyserver">"Verify keyserver"</string>
- <string name="label_enter_keyserver_url">"Enter keyserver URL"</string>
+ <string name="label_verify_keyserver_connection">"Test connection"</string>
+ <string name="label_only_trusted_keyserver">"Only trusted keyserver"</string>
+ <string name="label_enter_keyserver_url">"URL"</string>
<string name="label_keyserver_dialog_delete">"Delete keyserver"</string>
<string name="label_theme">"Theme"</string>
@@ -200,8 +206,8 @@
<string name="label_experimental_settings_desc_title">"Warning"</string>
<string name="label_experimental_settings_desc_summary">"These features are not yet finished or results of user experience/security research. Thus, don't rely on their security and please don't report issues you encounter!"</string>
- <string name="label_experimental_settings_word_confirm_title">"Word Confirm"</string>
- <string name="label_experimental_settings_word_confirm_summary">"Confirm keys with words instead of hexadecimal fingerprints"</string>
+ <string name="label_experimental_settings_word_confirm_title">"Phrase Confirmation"</string>
+ <string name="label_experimental_settings_word_confirm_summary">"Confirm keys with phrases instead of hexadecimal fingerprints"</string>
<string name="label_experimental_settings_linked_identities_title">"Linked Identities"</string>
<string name="label_experimental_settings_linked_identities_summary">"Link keys to Twitter, GitHub, websites or DNS (similar to keybase.io but decentralized)"</string>
<string name="label_experimental_settings_keybase_title">"Keybase.io Proofs"</string>
@@ -223,22 +229,22 @@
<string name="pref_proxy_type_choice_socks">"SOCKS"</string>
<!-- OrbotHelper strings -->
- <string name="orbot_ignore_tor">"Don\'t use Tor"</string>
+ <string name="orbot_ignore_tor">"Don't use Tor"</string>
<!-- InstallDialogFragment strings -->
<string name="orbot_install_dialog_title">Install Orbot to use Tor?</string>
<string name="orbot_install_dialog_install">"Install"</string>
<string name="orbot_install_dialog_content">You must have Orbot installed and activated to proxy traffic through it. Would you like to install it?</string>
<string name="orbot_install_dialog_cancel">"Cancel"</string>
- <string name="orbot_install_dialog_ignore_tor">"Don\'t use Tor"</string>
+ <string name="orbot_install_dialog_ignore_tor">"Don't use Tor"</string>
<!-- StartOrbotDialogFragment strings -->
<string name="orbot_start_dialog_title">Start Orbot?</string>
- <string name="orbot_start_dialog_content">"Orbot doesn\'t appear to be running. Would you like to start it up and connect to Tor?"</string>
+ <string name="orbot_start_dialog_content">"Orbot doesn't appear to be running. Would you like to start it up and connect to Tor?"</string>
<string name="orbot_start_btn">"Start Orbot"</string>
<string name="orbot_start_dialog_start">"Start Orbot"</string>
<string name="orbot_start_dialog_cancel">"Cancel"</string>
- <string name="orbot_start_dialog_ignore_tor">"Don\'t use Tor"</string>
+ <string name="orbot_start_dialog_ignore_tor">"Don't use Tor"</string>
<string name="user_id_no_name"><![CDATA[<no name>]]></string>
@@ -293,7 +299,8 @@
<string name="no_filemanager_installed">"No compatible file manager installed."</string>
<string name="passphrases_do_not_match">"The passwords didn't match."</string>
<string name="passphrase_must_not_be_empty">"Please enter a password."</string>
- <string name="passphrase_for_symmetric_encryption">"Symmetric encryption."</string>
+ <string name="passphrase_for_symmetric_encryption">"Enter password"</string>
+ <string name="passphrase_for_backup">"Enter backup code"</string>
<string name="passphrase_for">"Enter password for '%s'"</string>
<string name="pin_for">"Enter PIN for '%s'"</string>
<string name="yubikey_pin_for">"Enter PIN to access YubiKey for '%s'"</string>
@@ -316,7 +323,7 @@
<string name="specify_backup_dest_secret_single">"A full backup of your key will be made, please specify a destination file.\nWARNING: File will be overwritten if it exists!"</string>
<string name="specify_backup_dest_secret">"A full backup of all keys including yours will be made, please specify a destination file.\nWARNING: File will be overwritten if it exists!"</string>
<string name="key_deletion_confirmation_multi">"Do you really want to delete all selected keys?"</string>
- <string name="secret_key_deletion_confirmation">"After deletion you will not be able to read messages encrypted with this key and lose all key confirmations done with it!"</string>
+ <string name="secret_key_deletion_confirmation">"After deletion you will not be able to decrypt messages/files encrypted with this key and lose all key confirmations done with it!"</string>
<string name="public_key_deletetion_confirmation">"Delete key '%s'?"</string>
<string name="also_export_secret_keys">"Also export secret keys"</string>
<string name="reinstall_openkeychain">"You encountered a known bug with Android. Please reinstall OpenKeychain if you want to link your contacts with keys."</string>
@@ -337,7 +344,6 @@
<string name="key_copied_to_clipboard">"Key has been copied to the clipboard!"</string>
<string name="fingerprint_copied_to_clipboard">"Fingerprint has been copied to the clipboard!"</string>
<string name="select_key_to_certify">"Please select a key to be used for confirmation!"</string>
- <string name="key_too_big_for_sharing">"Key is too big to be shared this way!"</string>
<string name="text_copied_to_clipboard">"Text has been copied to the clipboard!"</string>
<!--
@@ -397,6 +403,7 @@
<string name="progress_cancelling">"cancelling…"</string>
<string name="progress_saving">"saving…"</string>
<string name="progress_importing">"importing…"</string>
+ <string name="progress_benchmarking">"benchmarking…"</string>
<string name="progress_revoking_uploading">"Revoking and uploading key…"</string>
<string name="progress_updating">"Updating keys…"</string>
<string name="progress_exporting">"exporting…"</string>
@@ -436,8 +443,8 @@
<string name="progress_encrypting">"encrypting data…"</string>
<string name="progress_decrypting">"decrypting data…"</string>
<string name="progress_preparing_signature">"preparing signature…"</string>
+ <string name="progress_processing_signature">processing signature…</string>
<string name="progress_generating_signature">"generating signature…"</string>
- <string name="progress_processing_signature">"processing signature…"</string>
<string name="progress_verifying_signature">"verifying signature…"</string>
<string name="progress_signing">"signing…"</string>
<string name="progress_certifying">"certifying…"</string>
@@ -451,7 +458,7 @@
<string name="progress_con_saving">"consolidate: saving to cache…"</string>
<string name="progress_con_reimport">"consolidate: reimporting…"</string>
- <string name="progress_verifying_keyserver_url">"verifying keyserver…"</string>
+ <string name="progress_verifying_keyserver_connection">"verifying connection…"</string>
<string name="progress_starting_orbot">"Starting Orbot…"</string>
@@ -459,10 +466,6 @@
<string name="hint_cloud_search_hint">"Search via Name, Email…"</string>
<!-- key bit length selections -->
- <string name="key_size_512">"512"</string>
- <string name="key_size_768">"768"</string>
- <string name="key_size_1024">"1024"</string>
- <string name="key_size_1536">"1536"</string>
<string name="key_size_2048">"2048"</string>
<string name="key_size_3072">"3072"</string>
<string name="key_size_4096">"4096"</string>
@@ -686,7 +689,6 @@
<string name="key_trust_no_cloud_evidence">"No proof from the Internet on this key’s trustworthiness."</string>
<string name="key_trust_start_cloud_search">"Start search"</string>
<string name="key_trust_results_prefix">"Keybase.io offers “proofs” which assert that the owner of this key: "</string>
- <string name="key_trust_header_text">"Note: Keybase.io proofs are an experimental feature of OpenKeychain. We encourage you to scan QR Codes or exchange keys via NFC in addition to confirming them."</string>
<!-- keybase proof stuff -->
<string name="keybase_narrative_twitter">"Posts to Twitter as %s"</string>
@@ -763,13 +765,14 @@
<string name="create_key_add_email_text">"Additional email addresses are also associated to this key and can be used for secure communication."</string>
<string name="create_key_email_already_exists_text">"Email address has already been added"</string>
<string name="create_key_email_invalid_email">"Email address format is invalid"</string>
- <string name="create_key_yubi_key_pin_text">"Please remember the PIN, it is required to use your YubiKey later. Please write down the Admin PIN and store it in a safe place."</string>
+ <string name="create_key_yubi_key_pin_text">"Please choose a PIN with 6 numbers."</string>
+ <string name="create_key_yubi_key_admin_pin_text">"Please write down the Admin PIN and store it in a safe place (required when you used a wrong PIN 3 times)."</string>
<string name="create_key_yubi_key_pin">"PIN"</string>
<string name="create_key_yubi_key_admin_pin">"Admin PIN"</string>
- <string name="create_key_yubi_key_pin_repeat_text">"Please enter the PIN and Admin PIN to proceed."</string>
<string name="create_key_yubi_key_pin_repeat">"Repeat PIN"</string>
- <string name="create_key_yubi_key_admin_pin_repeat">"Repeat Admin PIN"</string>
<string name="create_key_yubi_key_pin_not_correct">"PIN is not correct!"</string>
+ <string name="create_key_yubi_key_pin_too_short">"PIN must be at least 6 numbers long!"</string>
+ <string name="create_key_yubi_key_pin_insecure">"Please choose a secure PIN, not 000000, 123456 or similar combinations."</string>
<!-- View key -->
<string name="view_key_revoked">"Revoked: Key must not be used anymore!"</string>
@@ -784,9 +787,10 @@
<!-- Add/Edit keyserver -->
<string name="add_keyserver_dialog_title">"Add keyserver"</string>
<string name="edit_keyserver_dialog_title">"Edit keyserver"</string>
- <string name="add_keyserver_verified">"Keyserver verified!"</string>
+ <string name="add_keyserver_connection_verified">"Connection verified!"</string>
<string name="add_keyserver_without_verification">"Keyserver added without verification."</string>
<string name="add_keyserver_invalid_url">"Invalid URL!"</string>
+ <string name="add_keyserver_keyserver_not_trusted">"Keyserver is not one of the trusted ones (no pinned certificate available)!"</string>
<string name="add_keyserver_connection_failed">"Failed to connect to keyserver. Please check the URL and your Internet connection."</string>
<string name="keyserver_preference_deleted">"%s deleted"</string>
<string name="keyserver_preference_cannot_delete_last">"Cannot delete last keyserver. At least one is required!"</string>
@@ -798,7 +802,7 @@
<string name="drawer_open">"Open navigation drawer"</string>
<string name="drawer_close">"Close navigation drawer"</string>
<string name="my_keys">"My Keys"</string>
- <string name="nav_backup">"Backup"</string>
+ <string name="nav_backup">"Backup/Restore"</string>
<!-- hints -->
<string name="encrypt_content_edit_text_hint">"Type text"</string>
@@ -995,6 +999,7 @@
<string name="msg_kc_uid_no_cert">"No valid self-certificate found for user ID '%s', removing from ring"</string>
<string name="msg_kc_uid_remove">"Removing invalid user ID '%s'"</string>
<string name="msg_kc_uid_dup">"Removing duplicate user ID '%s'. The keyring contained two of them. This may result in missing certificates!"</string>
+ <string name="msg_kc_uid_too_many">"Removing user ID '%s'. More than 100 User IDs are not imported!"</string>
<string name="msg_kc_uid_warn_encoding">"User ID does not verify as UTF-8!"</string>
<string name="msg_kc_uat_jpeg">"Processing user attribute of type JPEG"</string>
<string name="msg_kc_uat_unknown">"Processing user attribute of unknown type"</string>
@@ -1028,7 +1033,7 @@
<string name="msg_cr_error_no_user_id">"Keyrings must be created with at least one user ID!"</string>
<string name="msg_cr_error_no_certify">"Master key must have certify flag!"</string>
<string name="msg_cr_error_null_expiry">"Expiry time cannot be 'same as before' on key creation. This is a programming error, please file a bug report!"</string>
- <string name="msg_cr_error_keysize_512">"Key size must be greater or equal 512!"</string>
+ <string name="msg_cr_error_keysize_2048">"Key size must be greater or equal 2048!"</string>
<string name="msg_cr_error_no_curve">"No key size specified! This is a programming error, please file a bug report!"</string>
<string name="msg_cr_error_no_keysize">"No elliptic curve specified! This is a programming error, please file a bug report!"</string>
<string name="msg_cr_error_internal_pgp">"Internal OpenPGP error!"</string>
@@ -1151,10 +1156,13 @@
<string name="msg_ek_error_not_found">"Key not found!"</string>
<!-- Messages for DecryptVerify operation -->
+ <string name="msg_dc_askip_bad_flags">"Key is not an encryption key, skipping…"</string>
+ <string name="msg_dc_askip_unavailable">"Key not available, skipping…"</string>
<string name="msg_dc_askip_no_key">"Data not encrypted with known key, skipping…"</string>
<string name="msg_dc_askip_not_allowed">"Data not encrypted with allowed key, skipping…"</string>
<string name="msg_dc_asym">"Found block of asymmetrically encrypted data for key %s"</string>
<string name="msg_dc_charset">"Found charset header: '%s'"</string>
+ <string name="msg_dc_backup_version">"Found backupVersion header: '%s'"</string>
<string name="msg_dc_clear_data">"Processing literal data"</string>
<string name="msg_dc_clear_decompress">"Unpacking compressed data"</string>
<string name="msg_dc_clear_meta_file">"Filename: %s"</string>
@@ -1177,6 +1185,7 @@
<string name="msg_dc_error_input">"Error opening input data stream!"</string>
<string name="msg_dc_error_no_data">"No encrypted data found in stream!"</string>
<string name="msg_dc_error_no_key">"No encrypted data with known secret key found in stream!"</string>
+ <string name="msg_dc_error_no_signature">"Missing signature data!"</string>
<string name="msg_dc_error_pgp_exception">"Encountered OpenPGP Exception during operation!"</string>
<string name="msg_dc_integrity_check_ok">"Integrity check OK!"</string>
<string name="msg_dc_ok_meta_only">"Only metadata was requested, skipping decryption"</string>
@@ -1200,8 +1209,9 @@
<!-- Messages for VerifySignedLiteralData operation -->
<string name="msg_vl">"Starting signature check"</string>
- <string name="msg_vl_error_no_siglist">"No signature list in signed literal data"</string>
- <string name="msg_vl_error_wrong_key">"Message not signed with right key"</string>
+ <string name="msg_vl_error_no_siglist">"No signature list in signed literal data!"</string>
+ <string name="msg_vl_error_wrong_key">"Message not signed with expected key!"</string>
+ <string name="msg_vl_error_no_signature">"Missing signature data!"</string>
<string name="msg_vl_error_missing_literal">"No payload in signed literal data"</string>
<string name="msg_vl_clear_meta_file">"Filename: %s"</string>
<string name="msg_vl_clear_meta_mime">"MIME type: %s"</string>
@@ -1223,7 +1233,6 @@
<!-- Messages for PgpSignEncrypt operation -->
<string name="msg_pse_asymmetric">"Preparing public keys for encryption"</string>
- <string name="msg_pse_clearsign_only">"Signing of cleartext input not supported!"</string>
<string name="msg_pse_compressing">"Preparing compression"</string>
<string name="msg_pse_encrypting">"Encrypting data"</string>
<string name="msg_pse_error_bad_passphrase">"Bad password!"</string>
@@ -1294,26 +1303,28 @@
<string name="msg_import_partial">"Import operation successful, with errors!"</string>
<string name="msg_import_success">"Import operation successful!"</string>
- <plurals name="msg_export">
- <item quantity="one">"Exporting one key"</item>
- <item quantity="other">"Exporting %d keys"</item>
+ <plurals name="msg_backup">
+ <item quantity="one">"Backup with one key"</item>
+ <item quantity="other">"Backup with %d keys"</item>
</plurals>
- <string name="msg_export_file_name">"Filename: %s"</string>
- <string name="msg_export_all">"Exporting all keys"</string>
- <string name="msg_export_public">"Exporting public key %s"</string>
- <string name="msg_export_upload_public">"Uploading public key %s"</string>
- <string name="msg_export_secret">"Exporting secret key %s"</string>
- <string name="msg_export_error_no_file">"No filename specified!"</string>
- <string name="msg_export_error_fopen">"Error opening file!"</string>
- <string name="msg_export_error_no_uri">"No URI specified!"</string>
- <string name="msg_export_error_uri_open">"Error opening URI stream!"</string>
- <string name="msg_export_error_storage">"Storage is not ready for writing!"</string>
- <string name="msg_export_error_db">"Database error!"</string>
- <string name="msg_export_error_io">"Input/output error!"</string>
- <string name="msg_export_error_key">"Error preprocessing key data!"</string>
- <string name="msg_export_error_upload">"Error uploading key to server! Please check your Internet connection"</string>
- <string name="msg_export_success">"Export operation successful"</string>
- <string name="msg_export_upload_success">"Upload to keyserver successful"</string>
+ <string name="msg_backup_all">"Backup with all keys"</string>
+ <string name="msg_backup_public">"Creating backup of public key %s"</string>
+ <string name="msg_backup_secret">"Creating backup of secret key %s"</string>
+ <string name="msg_backup_error_uri_open">"Error opening URI stream!"</string>
+ <string name="msg_backup_error_db">"Database error!"</string>
+ <string name="msg_backup_error_io">"Input/output error!"</string>
+ <string name="msg_backup_success">"Backup operation successful"</string>
+
+ <string name="msg_upload">"Uploading public key"</string>
+ <string name="msg_upload_proxy_direct">"Using proxy: None"</string>
+ <string name="msg_upload_proxy_tor">"Using proxy: TOR"</string>
+ <string name="msg_upload_proxy">"Using proxy: %s"</string>
+ <string name="msg_upload_server">"Server: %s"</string>
+ <string name="msg_upload_key">"Key id: %s"</string>
+ <string name="msg_upload_error_key">"Error preprocessing key data!"</string>
+ <string name="msg_upload_error_not_found">"Key not found!"</string>
+ <string name="msg_upload_error_upload">"Error uploading key to server! Please check your Internet connection"</string>
+ <string name="msg_upload_success">"Upload to keyserver successful"</string>
<string name="msg_del_error_empty">"Nothing to delete!"</string>
<string name="msg_del_error_multi_secret">"Secret keys can only be deleted individually!"</string>
@@ -1361,6 +1372,15 @@
<string name="msg_lv_fetch_error_format">"Format error!"</string>
<string name="msg_lv_fetch_error_nothing">"Resource not found!"</string>
+ <string name="msg_bench">"Benchmarking some operations…"</string>
+ <string name="msg_bench_enc_time">"Encryption time: %ss"</string>
+ <string name="msg_bench_enc_time_avg">"Average time to encrypt 5M: %ss"</string>
+ <string name="msg_bench_dec_time">"Decryption time: %ss"</string>
+ <string name="msg_bench_dec_time_avg">"Average time to decrypt 5M: %ss"</string>
+ <string name="msg_bench_s2k_100ms_its">"S2K Iteration Count for 100ms: %s"</string>
+ <string name="msg_bench_s2k_for_it">"Time for %1$s SHA1 S2K iterations: %2$sms"</string>
+ <string name="msg_bench_success">"Benchmarking complete!"</string>
+
<string name="msg_data">"Processing input data"</string>
<string name="msg_data_openpgp">"Attempting to process OpenPGP data"</string>
<string name="msg_data_detached">"Encountered detached signature"</string>
@@ -1371,9 +1391,9 @@
<string name="msg_data_detached_trailing">"Skipping trailing data after signed part!"</string>
<string name="msg_data_detached_unsupported">"Unsupported type of detached signature!"</string>
<string name="msg_data_error_io">"Error reading input data!"</string>
- <string name="msg_data_error_openpgp">"Error processing OpenPGP data!"</string>
<string name="msg_data_mime_bad">"Could not parse as MIME data"</string>
<string name="msg_data_mime_filename">"Filename: '%s'"</string>
+ <string name="msg_data_mime_from_extension">"Guessing MIME type from extension"</string>
<string name="msg_data_mime_length">"Content-Length: %s"</string>
<string name="msg_data_mime">"Parsing MIME data structure"</string>
<string name="msg_data_mime_ok">"Finished parsing</string>
@@ -1441,6 +1461,7 @@
<string name="backup_all">"All keys + your own keys"</string>
<string name="backup_public_keys">"All keys"</string>
<string name="backup_section">"Backup"</string>
+ <string name="restore_section">"Restore"</string>
<!-- unsorted -->
<string name="section_certifier_id">"Certifier"</string>
@@ -1451,9 +1472,8 @@
<string name="certs_text">"Only validated self-certificates and validated certificates created with your keys are displayed here."</string>
<string name="section_uids_to_certify">"Identities for "</string>
<string name="certify_text">"The keys you are importing contain “identities”: names and email addresses. Select exactly those for confirmation which match what you expected."</string>
- <string name="certify_fingerprint_text">"Compare the displayed fingerprint, character by character, with the one displayed on your partners device."</string>
- <string name="certify_fingerprint_text_words">"Compare the displayed fingerprint, word by word, with the one displayed on your partners device."</string>
- <string name="certify_fingerprint_text2">"Do the fingerprints match?"</string>
+ <string name="certify_fingerprint_text">"Compare the fingerprint, character by character, with the one displayed on your partner’s device."</string>
+ <string name="certify_fingerprint_text_phrases">"Compare these phrases with the ones displayed on your partner’s device."</string>
<string name="label_revocation">"Revocation Reason"</string>
<string name="label_cert_type">"Type"</string>
<string name="error_key_not_found">"Key not found!"</string>
@@ -1521,7 +1541,12 @@
<string name="yubikey_status_unbound">"YubiKey matches, can be bound to key"</string>
<string name="yubikey_status_partly">"YubiKey matches, partly bound to key"</string>
<string name="yubikey_create">"Hold YubiKey against the back of your device."</string>
+ <string name="yubikey_reset_or_import">"This YubiKey already contains a key. You can import the key using the cloud or reset the YubiKey."</string>
<string name="btn_import">"Import"</string>
+ <string name="btn_reset">"Reset"</string>
+ <string name="yubikey_import_radio">"Import key"</string>
+ <string name="yubikey_reset_radio">"Reset YubiKey"</string>
+ <string name="yubikey_reset_warning">"Resetting the YubiKey completely destroys the keys on it. Afterwards, you will not be able to decrypt messages/files encrypted with this key!"</string>
<string name="snack_yubi_other">Different key stored on YubiKey!</string>
<string name="error_nfc">"NFC Error: %s"</string>
<plurals name="error_pin">
@@ -1539,8 +1564,9 @@
<string name="error_nfc_chaining_error">"YubiKey expected last command in a chain."</string>
<string name="error_nfc_header">"YubiKey reported invalid %s byte."</string>
<string name="error_nfc_tag_lost">"YubiKey has been taken off too early. Keep the YubiKey at the back until the operation finishes."</string>
+ <string name="error_nfc_iso_dep_not_supported">"Tag does not support ISO-DEP (ISO 14443-4)"</string>
<string name="error_nfc_try_again">"Try again"</string>
- <string name="error_pin_nodefault">Default PIN was rejected!</string>
+ <string name="error_pin_wrong">PIN is wrong!</string>
<string name="error_temp_file">Error creating temporary file.</string>
<string name="btn_delete_original">Delete original file</string>
@@ -1557,6 +1583,7 @@
<string name="error_reading_k9">"Received incomplete data, try pressing 'Download complete message' in K-9 Mail!"</string>
<string name="filename_unknown">Unknown filename (click to open)</string>
<string name="filename_unknown_text">Text (click to show)</string>
+ <string name="filename_keys">"Key Backup (click to import)"</string>
<string name="intent_show">Show Signed/Encrypted Content</string>
<string name="intent_share">Share Signed/Encrypted Content</string>
<string name="view_internal">"View in OpenKeychain"</string>
@@ -1610,7 +1637,7 @@
</plurals>
<!-- Other Linked Identity strings -->
- <string name="linked_select_1">"A \'linked identity\' connects your pgp key to a resource on the web."</string>
+ <string name="linked_select_1">"A 'linked identity' connects your pgp key to a resource on the web."</string>
<string name="linked_select_2">"Please select a type:"</string>
<string name="linked_id_generic_text">"This file claims ownership of the OpenPGP key with long id %2$s.\n\nToken for proof:\n%1$s"</string>
<string name="linked_id_github_text">"This Gist confirms the Linked Identity in my OpenPGP key, and links it to this GitHub account.\n\nToken for proof:\n%1$s"</string>
@@ -1628,7 +1655,8 @@
<string name="linked_title_twitter">"Twitter"</string>
<string name="card_linked_identity">"Linked Identity"</string>
<string name="linked_button_verify">"Verify"</string>
- <string name="linked_button_retry">"Retry last step"</string>
+ <string name="linked_button_retry">"Retry"</string>
+ <string name="linked_button_retry_step">"Retry last step"</string>
<string name="linked_button_confirm">"Confirm"</string>
<string name="linked_button_view">"View"</string>
<string name="linked_text_verifying">"Verifying…"</string>
@@ -1647,5 +1675,28 @@
<string name="linked_error_http">"Communication error: %s"</string>
<string name="linked_webview_title_github">"GitHub Authorization"</string>
<string name="linked_gist_description">"OpenKeychain API Tests"</string>
+ <string name="snack_btn_overwrite">"Overwrite"</string>
+ <string name="backup_code_explanation">"The backup will be secured with a backup code. Write it down before you proceed!"</string>
+ <string name="backup_code_enter">"Please enter the backup code:"</string>
+ <string name="backup_code_ok">"Code accepted!"</string>
+ <string name="btn_code_wrotedown">"OK, I wrote it down!"</string>
+ <string name="backup_code_wrong">"The backup code you entered is wrong!\nDid you write it down correctly?"</string>
+ <string name="btn_backup_share">"Share backup"</string>
+ <string name="btn_backup_save">"Save backup"</string>
+ <string name="snack_backup_error_saving">"Error saving backup!"</string>
+ <string name="snack_backup_saved">"Backup saved"</string>
+ <string name="snack_backup_exists">"Backup already exists!"</string>
+ <string name="snack_backup_saved_dir">"Saved to OpenKeychain directory"</string>
+ <string name="btn_backup_back">Go back to check</string>
+ <string name="snack_text_too_long">"Text is too long to show in full!"</string>
+ <string name="snack_shared_text_too_long">"Shared text was cut because it was too long!"</string>
+
+ <string name="share_log_dialog_title">"Share log?"</string>
+ <string name="share_log_dialog_message">"While logs can be super helpful for developers to find bugs in OpenKeychain, they can contain potential sensitive information such as data about the updated keys. Please make sure you are okay with sharing this information."</string>
+ <string name="share_log_dialog_share_button">"Share"</string>
+ <string name="share_log_dialog_cancel_button">"Cancel"</string>
+ <string name="toast_wrong_mimetype">"Wrong data type, expected text!"</string>
+ <string name="toast_no_text">"No text in shared data!"</string>
+ <string name="btn_search_for_query">"Search for\n'%s'"</string>
</resources>
diff --git a/OpenKeychain/src/main/res/values/themes.xml b/OpenKeychain/src/main/res/values/themes.xml
index 38cf8a3db..fc6ae3846 100644
--- a/OpenKeychain/src/main/res/values/themes.xml
+++ b/OpenKeychain/src/main/res/values/themes.xml
@@ -85,11 +85,9 @@
<item name="alertDialogTheme">@style/Theme.Keychain.Dark.Dialog.Alert</item>
</style>
- <style name="Theme.Keychain.Light" parent="Base.Theme.Keychain.Light">
- </style>
+ <style name="Theme.Keychain.Light" parent="Base.Theme.Keychain.Light"></style>
- <style name="Theme.Keychain.Dark" parent="Base.Theme.Keychain.Dark">
- </style>
+ <style name="Theme.Keychain.Dark" parent="Base.Theme.Keychain.Dark"></style>
<!-- http://android-developers.blogspot.de/2014/10/appcompat-v21-material-design-for-pre.html -->
<style name="Widget.Keychain.SearchView" parent="Widget.AppCompat.SearchView">
@@ -134,4 +132,6 @@
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
+
+ <style name="Theme.Keychain.Transparent" parent="@android:style/Theme.NoDisplay" />
</resources>
diff --git a/OpenKeychain/src/main/res/xml/gui_preferences.xml b/OpenKeychain/src/main/res/xml/gui_preferences.xml
deleted file mode 100644
index cda7beeef..000000000
--- a/OpenKeychain/src/main/res/xml/gui_preferences.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
- <ListPreference
- android:persistent="false"
- android:key="theme"
- android:title="@string/label_theme"
- android:entries="@array/theme_entries"
- android:entryValues="@array/theme_values"
- android:dialogTitle="@string/label_theme" />
-
-</PreferenceScreen>
diff --git a/OpenKeychain/src/main/res/xml/passphrase_preferences.xml b/OpenKeychain/src/main/res/xml/passphrase_preferences.xml
index 7dd649e5d..86de8a4b7 100644
--- a/OpenKeychain/src/main/res/xml/passphrase_preferences.xml
+++ b/OpenKeychain/src/main/res/xml/passphrase_preferences.xml
@@ -10,14 +10,8 @@
android:persistent="false"
android:title="@string/label_passphrase_cache_subs" />
<CheckBoxPreference
- android:key="useDefaultYubikeyPin"
- android:persistent="false"
- android:defaultValue="true"
- android:title="@string/label_use_default_yubikey_pin"
- android:summary="@string/label_label_use_default_yubikey_pin_summary" />
- <CheckBoxPreference
+ android:defaultValue="false"
android:key="useNumKeypadForYubikeyPin"
android:persistent="false"
- android:defaultValue="false"
android:title="@string/label_use_num_keypad_for_yubikey_pin" />
</PreferenceScreen>
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java
index c1aa5a76f..1475deca9 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/CertifyOperationTest.java
@@ -78,11 +78,11 @@ public class CertifyOperationTest {
{
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
+ Algorithm.RSA, 2048, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.DSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
+ Algorithm.DSA, 2048, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.ELGAMAL, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
+ Algorithm.ELGAMAL, 2048, null, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("derp");
parcel.mNewUnlock = new ChangeUnlockParcel(mKeyPhrase1);
@@ -96,11 +96,11 @@ public class CertifyOperationTest {
{
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
+ Algorithm.RSA, 2048, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.DSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
+ Algorithm.DSA, 2048, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.ELGAMAL, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
+ Algorithm.ELGAMAL, 2048, null, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("ditz");
byte[] uatdata = new byte[random.nextInt(150)+10];
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/ExportTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/ExportTest.java
index a659dc7da..29ba2bd19 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/ExportTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/ExportTest.java
@@ -17,40 +17,65 @@
package org.sufficientlysecure.keychain.operations;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.io.PrintStream;
+import java.security.Security;
+import java.util.Iterator;
+
+import android.app.Application;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.net.Uri;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.Robolectric;
import org.robolectric.RobolectricGradleTestRunner;
-import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLog;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.sufficientlysecure.keychain.WorkaroundBuildConfig;
-import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
+import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.operations.results.ExportResult;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
+import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
+import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing.IteratorWithIOThrow;
import org.sufficientlysecure.keychain.pgp.WrappedSignature;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
+import org.sufficientlysecure.keychain.service.BackupKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.ProgressScaler;
import org.sufficientlysecure.keychain.util.TestingUtils;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-import java.security.Security;
-import java.util.Iterator;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = WorkaroundBuildConfig.class, sdk = 21, manifest = "src/main/AndroidManifest.xml")
@@ -75,16 +100,16 @@ public class ExportTest {
{
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
+ Algorithm.RSA, 2048, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.DSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
+ Algorithm.DSA, 2048, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.ELGAMAL, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
+ Algorithm.ELGAMAL, 2048, null, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("snips");
parcel.mNewUnlock = new ChangeUnlockParcel(mKeyPhrase1);
PgpEditKeyResult result = op.createSecretKeyRing(parcel);
- Assert.assertTrue("initial test key creation must succeed", result.success());
+ assertTrue("initial test key creation must succeed", result.success());
Assert.assertNotNull("initial test key creation must succeed", result.getRing());
mStaticRing1 = result.getRing();
@@ -93,16 +118,16 @@ public class ExportTest {
{
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
+ Algorithm.RSA, 2048, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.DSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
+ Algorithm.DSA, 2048, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.ELGAMAL, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
+ Algorithm.ELGAMAL, 2048, null, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("snails");
parcel.mNewUnlock = new ChangeUnlockParcel(null, new Passphrase("1234"));
PgpEditKeyResult result = op.createSecretKeyRing(parcel);
- Assert.assertTrue("initial test key creation must succeed", result.success());
+ assertTrue("initial test key creation must succeed", result.success());
Assert.assertNotNull("initial test key creation must succeed", result.getRing());
mStaticRing2 = result.getRing();
@@ -125,17 +150,17 @@ public class ExportTest {
}
@Test
- public void testExportAll() throws Exception {
- ExportOperation op = new ExportOperation(RuntimeEnvironment.application,
+ public void testExportAllLocalStripped() throws Exception {
+ BackupOperation op = new BackupOperation(RuntimeEnvironment.application,
new ProviderHelper(RuntimeEnvironment.application), null);
// make sure there is a local cert (so the later checks that there are none are meaningful)
- Assert.assertTrue("second keyring has local certification", checkForLocal(mStaticRing2));
+ assertTrue("second keyring has local certification", checkForLocal(mStaticRing2));
ByteArrayOutputStream out = new ByteArrayOutputStream();
- ExportResult result = op.exportKeyRings(new OperationLog(), null, false, out);
+ boolean result = op.exportKeysToStream(new OperationLog(), null, false, out);
- Assert.assertTrue("export must be a success", result.success());
+ assertTrue("export must be a success", result);
long masterKeyId1, masterKeyId2;
if (mStaticRing1.getMasterKeyId() < mStaticRing2.getMasterKeyId()) {
@@ -150,70 +175,209 @@ public class ExportTest {
UncachedKeyRing.fromStream(new ByteArrayInputStream(out.toByteArray()));
{
- Assert.assertTrue("export must have two keys (1/2)", unc.hasNext());
+ assertTrue("export must have two keys (1/2)", unc.hasNext());
UncachedKeyRing ring = unc.next();
Assert.assertEquals("first exported key has correct masterkeyid",
masterKeyId1, ring.getMasterKeyId());
- Assert.assertFalse("first exported key must not be secret", ring.isSecret());
- Assert.assertFalse("there must be no local signatures in an exported keyring",
+ assertFalse("first exported key must not be secret", ring.isSecret());
+ assertFalse("there must be no local signatures in an exported keyring",
checkForLocal(ring));
}
{
- Assert.assertTrue("export must have two keys (2/2)", unc.hasNext());
+ assertTrue("export must have two keys (2/2)", unc.hasNext());
UncachedKeyRing ring = unc.next();
Assert.assertEquals("second exported key has correct masterkeyid",
masterKeyId2, ring.getMasterKeyId());
- Assert.assertFalse("second exported key must not be secret", ring.isSecret());
- Assert.assertFalse("there must be no local signatures in an exported keyring",
+ assertFalse("second exported key must not be secret", ring.isSecret());
+ assertFalse("there must be no local signatures in an exported keyring",
checkForLocal(ring));
}
out = new ByteArrayOutputStream();
- result = op.exportKeyRings(new OperationLog(), null, true, out);
+ result = op.exportKeysToStream(new OperationLog(), null, true, out);
- Assert.assertTrue("export must be a success", result.success());
+ assertTrue("export must be a success", result);
unc = UncachedKeyRing.fromStream(new ByteArrayInputStream(out.toByteArray()));
{
- Assert.assertTrue("export must have four keys (1/4)", unc.hasNext());
+ assertTrue("export must have four keys (1/4)", unc.hasNext());
UncachedKeyRing ring = unc.next();
Assert.assertEquals("1/4 exported key has correct masterkeyid",
masterKeyId1, ring.getMasterKeyId());
- Assert.assertFalse("1/4 exported key must not be public", ring.isSecret());
- Assert.assertFalse("there must be no local signatures in an exported keyring",
+ assertFalse("1/4 exported key must not be public", ring.isSecret());
+ assertFalse("there must be no local signatures in an exported keyring",
checkForLocal(ring));
- Assert.assertTrue("export must have four keys (2/4)", unc.hasNext());
+ assertTrue("export must have four keys (2/4)", unc.hasNext());
ring = unc.next();
Assert.assertEquals("2/4 exported key has correct masterkeyid",
masterKeyId1, ring.getMasterKeyId());
- Assert.assertTrue("2/4 exported key must be public", ring.isSecret());
- Assert.assertFalse("there must be no local signatures in an exported keyring",
+ assertTrue("2/4 exported key must be public", ring.isSecret());
+ assertFalse("there must be no local signatures in an exported keyring",
checkForLocal(ring));
}
{
- Assert.assertTrue("export must have four keys (3/4)", unc.hasNext());
+ assertTrue("export must have four keys (3/4)", unc.hasNext());
UncachedKeyRing ring = unc.next();
Assert.assertEquals("3/4 exported key has correct masterkeyid",
masterKeyId2, ring.getMasterKeyId());
- Assert.assertFalse("3/4 exported key must not be public", ring.isSecret());
- Assert.assertFalse("there must be no local signatures in an exported keyring",
+ assertFalse("3/4 exported key must not be public", ring.isSecret());
+ assertFalse("there must be no local signatures in an exported keyring",
checkForLocal(ring));
- Assert.assertTrue("export must have four keys (4/4)", unc.hasNext());
+ assertTrue("export must have four keys (4/4)", unc.hasNext());
ring = unc.next();
Assert.assertEquals("4/4 exported key has correct masterkeyid",
masterKeyId2, ring.getMasterKeyId());
- Assert.assertTrue("4/4 exported key must be public", ring.isSecret());
- Assert.assertFalse("there must be no local signatures in an exported keyring",
+ assertTrue("4/4 exported key must be public", ring.isSecret());
+ assertFalse("there must be no local signatures in an exported keyring",
checkForLocal(ring));
}
}
+ @Test
+ public void testExportUnencrypted() throws Exception {
+
+ ContentResolver mockResolver = mock(ContentResolver.class);
+
+ Uri fakeOutputUri = Uri.parse("content://fake/out/1");
+ ByteArrayOutputStream outStream1 = new ByteArrayOutputStream();
+ when(mockResolver.openOutputStream(fakeOutputUri)).thenReturn(outStream1);
+
+ Application spyApplication = spy(RuntimeEnvironment.application);
+ when(spyApplication.getContentResolver()).thenReturn(mockResolver);
+
+ BackupOperation op = new BackupOperation(spyApplication,
+ new ProviderHelper(RuntimeEnvironment.application), null);
+
+ BackupKeyringParcel parcel = new BackupKeyringParcel(null,
+ new long[] { mStaticRing1.getMasterKeyId() }, false, fakeOutputUri);
+
+ ExportResult result = op.execute(parcel, null);
+
+ verify(mockResolver).openOutputStream(fakeOutputUri);
+
+ assertTrue("export must succeed", result.success());
+
+ TestingUtils.assertArrayEqualsPrefix("exported data must start with ascii armor header",
+ "-----BEGIN PGP PUBLIC KEY BLOCK-----\n".getBytes(), outStream1.toByteArray());
+ TestingUtils.assertArrayEqualsSuffix("exported data must end with ascii armor header",
+ "-----END PGP PUBLIC KEY BLOCK-----\n".getBytes(), outStream1.toByteArray());
+
+ {
+ IteratorWithIOThrow<UncachedKeyRing> unc
+ = UncachedKeyRing.fromStream(new ByteArrayInputStream(outStream1.toByteArray()));
+
+ assertTrue("export must have one key", unc.hasNext());
+ UncachedKeyRing ring = unc.next();
+ Assert.assertEquals("exported key has correct masterkeyid",
+ mStaticRing1.getMasterKeyId(), ring.getMasterKeyId());
+ assertFalse("export must have exactly one key", unc.hasNext());
+ }
+
+ }
+
+ @Test
+ public void testExportEncrypted() throws Exception {
+
+
+ Application spyApplication;
+ ContentResolver mockResolver = mock(ContentResolver.class);
+
+ Uri fakePipedUri, fakeOutputUri;
+ ByteArrayOutputStream outStream; {
+
+ fakePipedUri = Uri.parse("content://fake/pipe/1");
+ PipedInputStream pipedInStream = new PipedInputStream(8192);
+ PipedOutputStream pipedOutStream = new PipedOutputStream(pipedInStream);
+ when(mockResolver.openOutputStream(fakePipedUri)).thenReturn(pipedOutStream);
+ when(mockResolver.openInputStream(fakePipedUri)).thenReturn(pipedInStream);
+ when(mockResolver.insert(eq(TemporaryFileProvider.CONTENT_URI), any(ContentValues.class)))
+ .thenReturn(fakePipedUri);
+
+ fakeOutputUri = Uri.parse("content://fake/out/1");
+ outStream = new ByteArrayOutputStream();
+ when(mockResolver.openOutputStream(fakeOutputUri)).thenReturn(outStream);
+
+ spyApplication = spy(RuntimeEnvironment.application);
+ when(spyApplication.getContentResolver()).thenReturn(mockResolver);
+ }
+
+ Passphrase passphrase = new Passphrase("abcde");
+
+ { // export encrypted
+ BackupOperation op = new BackupOperation(spyApplication,
+ new ProviderHelper(RuntimeEnvironment.application), null);
+
+ BackupKeyringParcel parcel = new BackupKeyringParcel(passphrase,
+ new long[] { mStaticRing1.getMasterKeyId() }, false, fakeOutputUri);
+
+ ExportResult result = op.execute(parcel, null);
+
+ verify(mockResolver).openOutputStream(fakePipedUri);
+ verify(mockResolver).openInputStream(fakePipedUri);
+ verify(mockResolver).openOutputStream(fakeOutputUri);
+
+ assertTrue("export must succeed", result.success());
+ TestingUtils.assertArrayEqualsPrefix("exported data must start with ascii armor header",
+ "-----BEGIN PGP MESSAGE-----\n".getBytes(), outStream.toByteArray());
+ }
+
+ {
+ PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(RuntimeEnvironment.application,
+ new ProviderHelper(RuntimeEnvironment.application), null);
+
+ PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(outStream.toByteArray());
+ input.setAllowSymmetricDecryption(true);
+
+ {
+ DecryptVerifyResult result = op.execute(input, new CryptoInputParcel());
+ assertTrue("decryption must return pending without passphrase", result.isPending());
+ Assert.assertTrue("should contain pending passphrase log entry",
+ result.getLog().containsType(LogType.MSG_DC_PENDING_PASSPHRASE));
+ }
+ {
+ DecryptVerifyResult result = op.execute(input, new CryptoInputParcel(new Passphrase("bad")));
+ assertFalse("decryption must fail with bad passphrase", result.success());
+ Assert.assertTrue("should contain bad passphrase log entry",
+ result.getLog().containsType(LogType.MSG_DC_ERROR_SYM_PASSPHRASE));
+ }
+
+ DecryptVerifyResult result = op.execute(input, new CryptoInputParcel(passphrase));
+ assertTrue("decryption must succeed with passphrase", result.success());
+
+ assertEquals("backup filename should be backup_keyid.pub.asc",
+ "backup_" + KeyFormattingUtils.convertKeyIdToHex(mStaticRing1.getMasterKeyId()) + ".pub.asc",
+ result.getDecryptionMetadata().getFilename());
+
+ assertEquals("mime type for pgp keys must be correctly detected",
+ "application/pgp-keys", result.getDecryptionMetadata().getMimeType());
+
+ TestingUtils.assertArrayEqualsPrefix("exported data must start with ascii armor header",
+ "-----BEGIN PGP PUBLIC KEY BLOCK-----\n".getBytes(), result.getOutputBytes());
+ TestingUtils.assertArrayEqualsSuffix("exported data must end with ascii armor header",
+ "-----END PGP PUBLIC KEY BLOCK-----\n".getBytes(), result.getOutputBytes());
+
+ {
+ IteratorWithIOThrow<UncachedKeyRing> unc
+ = UncachedKeyRing.fromStream(new ByteArrayInputStream(result.getOutputBytes()));
+
+ assertTrue("export must have one key", unc.hasNext());
+ UncachedKeyRing ring = unc.next();
+ Assert.assertEquals("exported key has correct masterkeyid",
+ mStaticRing1.getMasterKeyId(), ring.getMasterKeyId());
+ assertFalse("export must have exactly one key", unc.hasNext());
+ }
+
+ }
+
+ }
+
+
/** This function checks whether or not there are any local signatures in a keyring. */
private boolean checkForLocal(UncachedKeyRing ring) {
Iterator<WrappedSignature> sigs = ring.getPublicKey().getSignatures();
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java
index e6c8c0efe..717dfe508 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperationTest.java
@@ -74,11 +74,11 @@ public class PromoteKeyOperationTest {
{
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
+ Algorithm.RSA, 2048, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.DSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
+ Algorithm.DSA, 2048, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.ELGAMAL, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
+ Algorithm.ELGAMAL, 2048, null, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("derp");
parcel.mNewUnlock = new ChangeUnlockParcel(mKeyPhrase1);
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/InputDataOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/InputDataOperationTest.java
index 38af88a18..84d396af5 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/InputDataOperationTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/InputDataOperationTest.java
@@ -43,7 +43,7 @@ import org.sufficientlysecure.keychain.WorkaroundBuildConfig;
import org.sufficientlysecure.keychain.operations.InputDataOperation;
import org.sufficientlysecure.keychain.operations.results.InputDataResult;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
+import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
import org.sufficientlysecure.keychain.service.InputDataParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
@@ -117,7 +117,7 @@ public class InputDataOperationTest {
Uri fakeOutputUri1 = Uri.parse("content://fake/out/1");
Uri fakeOutputUri2 = Uri.parse("content://fake/out/2");
- when(mockResolver.insert(eq(TemporaryStorageProvider.CONTENT_URI), any(ContentValues.class)))
+ when(mockResolver.insert(eq(TemporaryFileProvider.CONTENT_URI), any(ContentValues.class)))
.thenReturn(fakeOutputUri1, fakeOutputUri2);
// application which returns mockresolver
@@ -145,10 +145,10 @@ public class InputDataOperationTest {
ContentValues contentValues = new ContentValues();
contentValues.put("name", "data.txt");
contentValues.put("mimetype", "text/plain");
- verify(mockResolver).insert(TemporaryStorageProvider.CONTENT_URI, contentValues);
+ verify(mockResolver).insert(TemporaryFileProvider.CONTENT_URI, contentValues);
contentValues.put("name", (String) null);
contentValues.put("mimetype", "text/testvalue");
- verify(mockResolver).insert(TemporaryStorageProvider.CONTENT_URI, contentValues);
+ verify(mockResolver).insert(TemporaryFileProvider.CONTENT_URI, contentValues);
// quoted-printable returns windows style line endings for some reason?
Assert.assertEquals("first part must have expected content",
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java
index cc5ef8038..47c7a20ea 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpEncryptDecryptTest.java
@@ -27,6 +27,7 @@ import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
+import org.apache.tools.ant.util.StringUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -45,6 +46,7 @@ import org.spongycastle.bcpg.PacketTags;
import org.spongycastle.bcpg.PublicKeyEncSessionPacket;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.openpgp.PGPKeyFlags;
import org.sufficientlysecure.keychain.WorkaroundBuildConfig;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
@@ -55,6 +57,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType;
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
@@ -77,7 +80,7 @@ public class PgpEncryptDecryptTest {
static UncachedKeyRing mStaticRing1, mStaticRing2, mStaticRingInsecure;
static Passphrase mKeyPhrase1 = TestingUtils.genPassphrase(true);
static Passphrase mKeyPhrase2 = TestingUtils.genPassphrase(true);
- static Passphrase mKeyPhraseInsecure = TestingUtils.genPassphrase(true);
+// static Passphrase mKeyPhraseInsecure = TestingUtils.genPassphrase(true);
static PrintStream oldShadowStream;
@@ -127,24 +130,24 @@ public class PgpEncryptDecryptTest {
mStaticRing2 = result.getRing();
}
- {
- // insecure (1024 bit) RSA key
- SaveKeyringParcel parcel = new SaveKeyringParcel();
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
- parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
- parcel.mAddUserIds.add("eve");
- parcel.mNewUnlock = new ChangeUnlockParcel(mKeyPhraseInsecure);
-
- PgpEditKeyResult result = op.createSecretKeyRing(parcel);
- Assert.assertTrue("initial test key creation must succeed", result.success());
- Assert.assertNotNull("initial test key creation must succeed", result.getRing());
-
- mStaticRingInsecure = result.getRing();
- }
+// {
+// // insecure (1024 bit) RSA key
+// SaveKeyringParcel parcel = new SaveKeyringParcel();
+// parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
+// Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
+// parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
+// Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
+// parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
+// Algorithm.RSA, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
+// parcel.mAddUserIds.add("eve");
+// parcel.mNewUnlock = new ChangeUnlockParcel(mKeyPhraseInsecure);
+//
+// PgpEditKeyResult result = op.createSecretKeyRing(parcel);
+// Assert.assertTrue("initial test key creation must succeed", result.success());
+// Assert.assertNotNull("initial test key creation must succeed", result.getRing());
+//
+// mStaticRingInsecure = result.getRing();
+// }
}
@@ -287,7 +290,7 @@ public class PgpEncryptDecryptTest {
}
@Test
- public void testAsymmetricSign() {
+ public void testAsymmetricSignLiteral() {
String plaintext = "dies ist ein plaintext ☭" + TestingUtils.genPassphrase(true);
byte[] ciphertext;
@@ -341,6 +344,121 @@ public class PgpEncryptDecryptTest {
}
@Test
+ public void testAsymmetricSignCleartext() {
+
+ String plaintext = "dies ist ein\r\nplaintext\n ☭" + TestingUtils.genPassphrase(true);
+ byte[] ciphertext;
+
+ { // encrypt data with key
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes());
+
+ PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application,
+ new ProviderHelper(RuntimeEnvironment.application), null);
+
+ InputData data = new InputData(in, in.available());
+ PgpSignEncryptInputParcel input = new PgpSignEncryptInputParcel();
+
+ // only sign, as cleartext
+ input.setSignatureMasterKeyId(mStaticRing1.getMasterKeyId());
+ input.setSignatureSubKeyId(KeyringTestingHelper.getSubkeyId(mStaticRing1, 1));
+ input.setCleartextSignature(true);
+ input.setEnableAsciiArmorOutput(true);
+ input.setDetachedSignature(false);
+
+ PgpSignEncryptResult result = op.execute(input, new CryptoInputParcel(mKeyPhrase1), data, out);
+ Assert.assertTrue("signing must succeed", result.success());
+
+ ciphertext = out.toByteArray();
+ }
+
+ Assert.assertTrue("clearsigned text must contain plaintext (ignoring newlines)",
+ new String(ciphertext).replace("\r\n", "").contains(plaintext.replace("\r", "").replace("\n", "")));
+
+ { // verification should succeed
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
+ InputData data = new InputData(in, in.available());
+
+ PgpDecryptVerifyOperation op = operationWithFakePassphraseCache(null, null, null);
+ PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel();
+ DecryptVerifyResult result = op.execute(input, new CryptoInputParcel(), data, out);
+
+ Assert.assertTrue("verification must succeed", result.success());
+
+ Assert.assertTrue("verification text should equal plaintext (ignoring newlines)",
+ new String(out.toByteArray()).replace(StringUtils.LINE_SEP, "")
+ .equals(plaintext.replace("\r", "").replace("\n", "")));
+ Assert.assertEquals("decryptionResult should be RESULT_NOT_ENCRYPTED",
+ OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED, result.getDecryptionResult().getResult());
+ Assert.assertEquals("signatureResult should be RESULT_VALID_CONFIRMED",
+ OpenPgpSignatureResult.RESULT_VALID_CONFIRMED, result.getSignatureResult().getResult());
+
+ OpenPgpMetadata metadata = result.getDecryptionMetadata();
+ Assert.assertEquals("filesize must be correct",
+ out.toByteArray().length, metadata.getOriginalSize());
+
+ }
+
+ }
+
+ @Test
+ public void testAsymmetricSignDetached() {
+
+ String plaintext = "dies ist ein plaintext ☭" + TestingUtils.genPassphrase(true);
+ byte[] detachedSignature;
+
+ { // encrypt data with key
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes());
+
+ PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application,
+ new ProviderHelper(RuntimeEnvironment.application), null);
+
+ InputData data = new InputData(in, in.available());
+ PgpSignEncryptInputParcel input = new PgpSignEncryptInputParcel();
+
+ // only sign, as cleartext
+ input.setSignatureMasterKeyId(mStaticRing1.getMasterKeyId());
+ input.setSignatureSubKeyId(KeyringTestingHelper.getSubkeyId(mStaticRing1, 1));
+ input.setDetachedSignature(true);
+
+ PgpSignEncryptResult result = op.execute(input, new CryptoInputParcel(mKeyPhrase1), data, out);
+ Assert.assertTrue("signing must succeed", result.success());
+
+ detachedSignature = result.getDetachedSignature();
+ }
+
+ { // verification should succeed
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes());
+ InputData data = new InputData(in, in.available());
+
+ PgpDecryptVerifyOperation op = operationWithFakePassphraseCache(null, null, null);
+ PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel();
+ input.setDetachedSignature(detachedSignature);
+ DecryptVerifyResult result = op.execute(input, new CryptoInputParcel(), data, out);
+
+ Assert.assertTrue("verification must succeed", result.success());
+ Assert.assertArrayEquals("verification text should equal plaintext (save for a newline)",
+ plaintext.getBytes(), out.toByteArray());
+ Assert.assertEquals("decryptionResult should be RESULT_NOT_ENCRYPTED",
+ OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED, result.getDecryptionResult().getResult());
+ Assert.assertEquals("signatureResult should be RESULT_VALID_CONFIRMED",
+ OpenPgpSignatureResult.RESULT_VALID_CONFIRMED, result.getSignatureResult().getResult());
+
+ // TODO should detached verify return any metadata?
+ // OpenPgpMetadata metadata = result.getDecryptionMetadata();
+ // Assert.assertEquals("filesize must be correct",
+ // out.toByteArray().length, metadata.getOriginalSize());
+
+ }
+
+ }
+
+ @Test
public void testAsymmetricEncryptDecrypt() {
String plaintext = "dies ist ein plaintext ☭" + TestingUtils.genPassphrase(true);
@@ -438,12 +556,14 @@ public class PgpEncryptDecryptTest {
}
@Test
- public void testAsymmetricMultiSubkeyEncrypt() throws Exception {
+ public void testMultiSubkeyEncryptSkipStripOrBadFlag() throws Exception {
String plaintext = "dies ist ein plaintext ☭" + TestingUtils.genPassphrase(true);
+ byte[] ciphertext;
+ long encKeyId1;
+
{ // encrypt data with key
- byte[] ciphertext;
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes());
@@ -473,7 +593,7 @@ public class PgpEncryptDecryptTest {
Packet p;
p = new BCPGInputStream(new ByteArrayInputStream(enc1.buf)).readPacket();
Assert.assertTrue("first packet must be session packet", p instanceof PublicKeyEncSessionPacket);
- long encKeyId1 = ((PublicKeyEncSessionPacket) p).getKeyID();
+ encKeyId1 = ((PublicKeyEncSessionPacket) p).getKeyID();
p = new BCPGInputStream(new ByteArrayInputStream(enc2.buf)).readPacket();
Assert.assertTrue("second packet must be session packet", p instanceof PublicKeyEncSessionPacket);
@@ -488,6 +608,57 @@ public class PgpEncryptDecryptTest {
}
+ { // strip first encrypted subkey, decryption should skip it
+
+ SaveKeyringParcel parcel =
+ new SaveKeyringParcel(mStaticRing1.getMasterKeyId(), mStaticRing1.getFingerprint());
+ parcel.mChangeSubKeys.add(new SubkeyChange(encKeyId1, true, false));
+ UncachedKeyRing modified = PgpKeyOperationTest.applyModificationWithChecks(parcel, mStaticRing1,
+ new ArrayList<RawPacket>(), new ArrayList<RawPacket>(),
+ new CryptoInputParcel(new Date(), mKeyPhrase1));
+
+ ProviderHelper providerHelper = new ProviderHelper(RuntimeEnvironment.application);
+ providerHelper.saveSecretKeyRing(modified, new ProgressScaler());
+
+ PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(RuntimeEnvironment.application,
+ new ProviderHelper(RuntimeEnvironment.application), null);
+ PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(ciphertext);
+ DecryptVerifyResult result = op.execute(input, new CryptoInputParcel(mKeyPhrase1));
+
+ Assert.assertTrue("decryption must succeed", result.success());
+ Assert.assertTrue("decryption must have skipped first key",
+ result.getLog().containsType(LogType.MSG_DC_ASKIP_UNAVAILABLE));
+ }
+
+ { // change flags of second encrypted subkey, decryption should skip it
+
+ SaveKeyringParcel parcel =
+ new SaveKeyringParcel(mStaticRing1.getMasterKeyId(), mStaticRing1.getFingerprint());
+ parcel.mChangeSubKeys.add(new SubkeyChange(encKeyId1, KeyFlags.CERTIFY_OTHER, null));
+ UncachedKeyRing modified = PgpKeyOperationTest.applyModificationWithChecks(parcel, mStaticRing1,
+ new ArrayList<RawPacket>(), new ArrayList<RawPacket>(),
+ new CryptoInputParcel(new Date(), mKeyPhrase1));
+
+ ProviderHelper providerHelper = new ProviderHelper(RuntimeEnvironment.application);
+ providerHelper.saveSecretKeyRing(modified, new ProgressScaler());
+
+ PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(RuntimeEnvironment.application,
+ new ProviderHelper(RuntimeEnvironment.application), null);
+ PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(ciphertext);
+ DecryptVerifyResult result = op.execute(input, new CryptoInputParcel(mKeyPhrase1));
+
+ Assert.assertTrue("decryption must succeed", result.success());
+ Assert.assertTrue("decryption must have skipped first key",
+ result.getLog().containsType(LogType.MSG_DC_ASKIP_BAD_FLAGS));
+ }
+
+ }
+
+ @Test
+ public void testMultiSubkeyEncryptSkipRevoked() throws Exception {
+
+ String plaintext = "dies ist ein plaintext ☭" + TestingUtils.genPassphrase(true);
+
{ // revoke first encryption subkey of keyring in database
SaveKeyringParcel parcel = new SaveKeyringParcel(mStaticRing1.getMasterKeyId(), mStaticRing1.getFingerprint());
parcel.mRevokeSubKeys.add(KeyringTestingHelper.getSubkeyId(mStaticRing1, 2));
@@ -500,7 +671,6 @@ public class PgpEncryptDecryptTest {
}
{ // encrypt to this keyring, make sure it's not encrypted to the revoked subkey
- byte[] ciphertext;
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes());
@@ -518,7 +688,7 @@ public class PgpEncryptDecryptTest {
data, out);
Assert.assertTrue("encryption must succeed", result.success());
- ciphertext = out.toByteArray();
+ byte[] ciphertext = out.toByteArray();
Iterator<RawPacket> packets = KeyringTestingHelper.parseKeyring(ciphertext);
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
index c0e28cd4b..a62b4dbb2 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperationTest.java
@@ -82,8 +82,8 @@ public class PgpKeyOperationTest {
UncachedKeyRing ring;
PgpKeyOperation op;
SaveKeyringParcel parcel;
- ArrayList<RawPacket> onlyA = new ArrayList<RawPacket>();
- ArrayList<RawPacket> onlyB = new ArrayList<RawPacket>();
+ ArrayList<RawPacket> onlyA = new ArrayList<>();
+ ArrayList<RawPacket> onlyB = new ArrayList<>();
static CryptoInputParcel cryptoInput;
@@ -94,11 +94,11 @@ public class PgpKeyOperationTest {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.DSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
+ Algorithm.DSA, 3072, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
Algorithm.RSA, 2048, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
+ Algorithm.RSA, 3072, null, KeyFlags.ENCRYPT_COMMS, 0L));
parcel.mAddUserIds.add("twi");
parcel.mAddUserIds.add("pink");
@@ -153,13 +153,13 @@ public class PgpKeyOperationTest {
parcel.mNewUnlock = new ChangeUnlockParcel(passphrase);
assertFailure("creating ring with < 512 bytes keysize should fail", parcel,
- LogType.MSG_CR_ERROR_KEYSIZE_512);
+ LogType.MSG_CR_ERROR_KEYSIZE_2048);
}
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.ELGAMAL, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
+ Algorithm.ELGAMAL, 2048, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("shy");
parcel.mNewUnlock = new ChangeUnlockParcel(passphrase);
@@ -170,7 +170,7 @@ public class PgpKeyOperationTest {
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, null));
+ Algorithm.RSA, 2048, null, KeyFlags.CERTIFY_OTHER, null));
parcel.mAddUserIds.add("lotus");
parcel.mNewUnlock = new ChangeUnlockParcel(passphrase);
@@ -181,7 +181,7 @@ public class PgpKeyOperationTest {
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
+ Algorithm.RSA, 2048, null, KeyFlags.SIGN_DATA, 0L));
parcel.mAddUserIds.add("shy");
parcel.mNewUnlock = new ChangeUnlockParcel(passphrase);
@@ -192,7 +192,7 @@ public class PgpKeyOperationTest {
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
+ Algorithm.RSA, 2048, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mNewUnlock = new ChangeUnlockParcel(passphrase);
assertFailure("creating ring without user ids should fail", parcel,
@@ -216,7 +216,7 @@ public class PgpKeyOperationTest {
public void testMasterFlags() throws Exception {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA, 0L));
+ Algorithm.RSA, 4096, null, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA, 0L));
parcel.mAddUserIds.add("luna");
ring = assertCreateSuccess("creating ring with master key flags must succeed", parcel);
@@ -256,8 +256,8 @@ public class PgpKeyOperationTest {
List<UncachedPublicKey> subkeys = KeyringTestingHelper.itToList(ring.getPublicKeys());
Assert.assertEquals("number of subkeys must be three", 3, subkeys.size());
- Assert.assertTrue("key ring should have been created in the last 120 seconds",
- ring.getPublicKey().getCreationTime().after(new Date(new Date().getTime()-1000*120)));
+ Assert.assertTrue("key ring should have been created in the last 360 seconds",
+ ring.getPublicKey().getCreationTime().after(new Date(new Date().getTime()-1000*360)));
Assert.assertNull("key ring should not expire",
ring.getPublicKey().getUnsafeExpiryTimeForTesting());
@@ -347,7 +347,7 @@ public class PgpKeyOperationTest {
long expiry = new Date().getTime() / 1000 + 159;
int flags = KeyFlags.SIGN_DATA;
- int bits = 1024 + new Random().nextInt(8);
+ int bits = 2048 + new Random().nextInt(8);
parcel.mAddSubKeys.add(new SubkeyAdd(Algorithm.RSA, bits, null, flags, expiry));
UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB);
@@ -391,14 +391,14 @@ public class PgpKeyOperationTest {
parcel.mAddSubKeys.add(new SubkeyAdd(
Algorithm.RSA, new Random().nextInt(512), null, KeyFlags.SIGN_DATA, 0L));
assertModifyFailure("creating a subkey with keysize < 512 should fail", ring, parcel,
- LogType.MSG_CR_ERROR_KEYSIZE_512);
+ LogType.MSG_CR_ERROR_KEYSIZE_2048);
}
{
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, null));
+ Algorithm.RSA, 2048, null, KeyFlags.SIGN_DATA, null));
assertModifyFailure("creating master key with null expiry should fail", ring, parcel,
LogType.MSG_MF_ERROR_NULL_EXPIRY);
@@ -406,7 +406,7 @@ public class PgpKeyOperationTest {
{ // a past expiry should fail
parcel.reset();
- parcel.mAddSubKeys.add(new SubkeyAdd(Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA,
+ parcel.mAddSubKeys.add(new SubkeyAdd(Algorithm.RSA, 2048, null, KeyFlags.SIGN_DATA,
new Date().getTime()/1000-10));
assertModifyFailure("creating subkey with past expiry date should fail", ring, parcel,
LogType.MSG_MF_ERROR_PAST_EXPIRY);
@@ -837,7 +837,7 @@ public class PgpKeyOperationTest {
UncachedKeyRing modified;
- { // keytocard should fail with BAD_NFC_SIZE when presented with the RSA-1024 key
+ { // keytocard should fail with BAD_NFC_SIZE when presented with the RSA-3072 key
long keyId = KeyringTestingHelper.getSubkeyId(ring, 2);
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, false, true));
@@ -846,7 +846,7 @@ public class PgpKeyOperationTest {
parcel, cryptoInput, LogType.MSG_MF_ERROR_BAD_NFC_SIZE);
}
- { // keytocard should fail with BAD_NFC_ALGO when presented with the DSA-1024 key
+ { // keytocard should fail with BAD_NFC_ALGO when presented with the DSA-3072 key
long keyId = KeyringTestingHelper.getSubkeyId(ring, 0);
parcel.reset();
parcel.mChangeSubKeys.add(new SubkeyChange(keyId, false, true));
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
index 5e552fecc..a077f5398 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringCanonicalizeTest.java
@@ -89,8 +89,8 @@ public class UncachedKeyringCanonicalizeTest {
static UncachedKeyRing staticRing;
static int totalPackets;
UncachedKeyRing ring;
- ArrayList<RawPacket> onlyA = new ArrayList<RawPacket>();
- ArrayList<RawPacket> onlyB = new ArrayList<RawPacket>();
+ ArrayList<RawPacket> onlyA = new ArrayList<>();
+ ArrayList<RawPacket> onlyB = new ArrayList<>();
OperationResult.OperationLog log = new OperationResult.OperationLog();
PGPSignatureSubpacketGenerator subHashedPacketsGen;
PGPSecretKey secretKey;
@@ -358,7 +358,7 @@ public class UncachedKeyringCanonicalizeTest {
SaveKeyringParcel parcel = new SaveKeyringParcel();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
+ Algorithm.RSA, 2048, null, KeyFlags.CERTIFY_OTHER, 0L));
parcel.mAddUserIds.add("trix");
PgpKeyOperation op = new PgpKeyOperation(null);
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
index 90189e377..59397e642 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringMergeTest.java
@@ -87,8 +87,8 @@ public class UncachedKeyringMergeTest {
static UncachedKeyRing staticRingA, staticRingB;
UncachedKeyRing ringA, ringB;
- ArrayList<RawPacket> onlyA = new ArrayList<RawPacket>();
- ArrayList<RawPacket> onlyB = new ArrayList<RawPacket>();
+ ArrayList<RawPacket> onlyA = new ArrayList<>();
+ ArrayList<RawPacket> onlyB = new ArrayList<>();
OperationResult.OperationLog log = new OperationResult.OperationLog();
PgpKeyOperation op;
SaveKeyringParcel parcel;
@@ -234,7 +234,7 @@ public class UncachedKeyringMergeTest {
parcel.reset();
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
- Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
+ Algorithm.RSA, 2048, null, KeyFlags.SIGN_DATA, 0L));
modifiedA = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date(), new Passphrase()), parcel).getRing();
modifiedB = op.modifySecretKeyRing(secretRing, new CryptoInputParcel(new Date(), new Passphrase()), parcel).getRing();
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
index 4cdcf0117..b870e5494 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/UncachedKeyringTest.java
@@ -28,6 +28,7 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLog;
import org.spongycastle.bcpg.sig.KeyFlags;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.sufficientlysecure.keychain.BuildConfig;
import org.sufficientlysecure.keychain.WorkaroundBuildConfig;
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
@@ -41,6 +42,7 @@ import org.sufficientlysecure.keychain.util.Passphrase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.security.Security;
import java.util.Iterator;
import java.util.Random;
@@ -53,6 +55,7 @@ public class UncachedKeyringTest {
@BeforeClass
public static void setUpOnce() throws Exception {
+ Security.insertProviderAt(new BouncyCastleProvider(), 1);
ShadowLog.stream = System.out;
SaveKeyringParcel parcel = new SaveKeyringParcel();
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/util/TestingUtils.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/util/TestingUtils.java
index 1d7952464..0b35aaf22 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/util/TestingUtils.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/util/TestingUtils.java
@@ -19,6 +19,9 @@ package org.sufficientlysecure.keychain.util;
import java.util.Random;
+import junit.framework.Assert;
+
+
public class TestingUtils {
public static Passphrase genPassphrase() {
return genPassphrase(false);
@@ -35,4 +38,25 @@ public class TestingUtils {
System.out.println("Generated passphrase: '" + passbuilder.toString() + "'");
return new Passphrase(passbuilder.toString());
}
+
+ public static void assertArrayEqualsPrefix(String msg, byte[] expected, byte[] actual) {
+
+ Assert.assertTrue("exepected must be shorter or equal to actual array length",
+ expected.length <= actual.length);
+ for (int i = 0; i < expected.length; i++) {
+ Assert.assertEquals(msg, expected[i], actual[i]);
+ }
+
+ }
+
+ public static void assertArrayEqualsSuffix(String msg, byte[] expected, byte[] actual) {
+
+ Assert.assertTrue("exepected must be shorter or equal to actual array length",
+ expected.length <= actual.length);
+ for (int i = 0; i < expected.length; i++) {
+ Assert.assertEquals(msg, expected[i], actual[actual.length -expected.length +i]);
+ }
+
+ }
+
}