aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2015-09-28 18:27:29 +0200
committerVincent Breitmoser <valodim@mugenguild.com>2015-09-28 18:27:29 +0200
commit0e613aff2e617ca12c1b2e1032b21334c2ca674a (patch)
tree4e16d6a086cbe12875454fba520241ac84e277c7
parentb65a23f2d46f905160b47e044de12cf9177dfd51 (diff)
parent3df9bea4554c0edddce57aa6a2e32cfe5250ed72 (diff)
downloadopen-keychain-0e613aff2e617ca12c1b2e1032b21334c2ca674a.tar.gz
open-keychain-0e613aff2e617ca12c1b2e1032b21334c2ca674a.tar.bz2
open-keychain-0e613aff2e617ca12c1b2e1032b21334c2ca674a.zip
Merge remote-tracking branch 'origin/master' into encrypted-export
-rwxr-xr-xGraphics/get-material-icons.sh1
-rw-r--r--OpenKeychain/build.gradle38
-rw-r--r--OpenKeychain/src/main/AndroidManifest.xml4
-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/sufficientlysecure/keychain/KeychainApplication.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/BitInputStream.java125
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/SentenceConfirm.java206
-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.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java73
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java11
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java74
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/KeybaseVerificationOperation.java35
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java11
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java42
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java45
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyserverFragment.java22
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeybaseFragment.java35
-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/FileDialogFragment.java234
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java15
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java84
-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.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/OkHttpKeybaseClient.java79
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java82
-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_check_black_24dp.pngbin0 -> 128 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-xxhdpi/ic_check_black_24dp.pngbin0 -> 254 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/add_keyserver_dialog.xml36
-rw-r--r--OpenKeychain/src/main/res/layout/certify_fingerprint_fragment.xml214
-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/key_view.xml2
-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/values-cs/strings.xml4
-rw-r--r--OpenKeychain/src/main/res/values-de/strings.xml6
-rw-r--r--OpenKeychain/src/main/res/values-es/strings.xml6
-rw-r--r--OpenKeychain/src/main/res/values-eu/strings.xml6
-rw-r--r--OpenKeychain/src/main/res/values-fa/strings.xml2
-rw-r--r--OpenKeychain/src/main/res/values-fr/strings.xml6
-rw-r--r--OpenKeychain/src/main/res/values-it/strings.xml2
-rw-r--r--OpenKeychain/src/main/res/values-ja/strings.xml6
-rw-r--r--OpenKeychain/src/main/res/values-nl/strings.xml6
-rw-r--r--OpenKeychain/src/main/res/values-ru/strings.xml6
-rw-r--r--OpenKeychain/src/main/res/values-sr/strings.xml6
-rw-r--r--OpenKeychain/src/main/res/values-sv/strings.xml6
-rw-r--r--OpenKeychain/src/main/res/values-zh-rTW/strings.xml6
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml28
-rw-r--r--README.md2
m---------extern/KeybaseLib0
71 files changed, 2100 insertions, 745 deletions
diff --git a/Graphics/get-material-icons.sh b/Graphics/get-material-icons.sh
index b6a2515c9..999680751 100755
--- a/Graphics/get-material-icons.sh
+++ b/Graphics/get-material-icons.sh
@@ -4,6 +4,7 @@ python copy OpenKeychain action white search 24
python copy OpenKeychain navigation white arrow_back 24
python copy OpenKeychain navigation white close 24
python copy OpenKeychain navigation white check 24
+python copy OpenKeychain navigation black check 24
python copy OpenKeychain navigation black expand_less 24
python copy OpenKeychain navigation black expand_more 24
python copy OpenKeychain navigation white refresh 24
diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle
index 9d29d0a98..39681fd05 100644
--- a/OpenKeychain/build.gradle
+++ b/OpenKeychain/build.gradle
@@ -57,7 +57,8 @@ dependencies {
compile 'com.mikepenz.iconics:meteocons-typeface:1.1.1@aar'
compile 'com.mikepenz.iconics:community-material-typeface:1.0.0@aar'
compile 'com.nispok:snackbar:2.11.0'
- compile 'com.squareup.okhttp:okhttp:2.4.0'
+ compile 'com.squareup.okhttp:okhttp:2.5.0'
+ compile 'com.squareup.okhttp:okhttp-urlconnection:2.5.0'
compile 'org.apache.james:apache-mime4j-core:0.7.2'
compile 'org.apache.james:apache-mime4j-dom:0.7.2'
compile 'org.thoughtcrime.ssl.pinning:AndroidPinning:1.0.0'
@@ -91,31 +92,38 @@ dependencyVerification {
'com.jpardogo.materialtabstrip:library:c6ef812fba4f74be7dc4a905faa4c2908cba261a94c13d4f96d5e67e4aad4aaa',
'com.getbase:floatingactionbutton:052aa2a94e49e5dccc97cb99f2add87e8698b84859f0e3ac181100c0bc7640ca',
'org.commonjava.googlecode.markdown4j:markdown4j:e952e825d29e1317d96f79f346bfb6786c7c5eef50bd26e54a80823704b62e13',
+ 'org.ocpsoft.prettytime:prettytime:a6bc2641b3ab7873df604b77b6680c75b86d98e78afefb367940972f925591b5',
'com.splitwise:tokenautocomplete:20bee71cc59b3828eb000b684d46ddf738efd56b8fee453a509cd16fda42c8cb',
'se.emilsjolander:stickylistheaders:8c05981ec5725be33f7cee5e68c13f3db49cd5c75f1aaeb04024920b1ef96ad4',
+ 'com.mikepenz:materialdrawer:70c3efb3842461db41df6a918ea93969a7da21e63c092be838b153e5a47a17bf',
'org.sufficientlysecure:html-textview:1d3bed31ef837437154de8d2362a0e6b0e59b6c3535d87ee48c2fab12c84f9bb',
+ 'com.mikepenz.iconics:octicons-typeface:67ed7d456a9ce5f5307b85f955797bfb3dd674e2f6defb31c6b8bbe2ede290be',
'com.mikepenz:iconics:c1a02203d8e0d638959463c00af3ab9096e0a7c1ad5928762eb10ef5ce8a63cd',
- 'com.mikepenz:materialdrawer:70c3efb3842461db41df6a918ea93969a7da21e63c092be838b153e5a47a17bf',
+ 'com.mikepenz.iconics:community-material-typeface:f1c5afee5f0f10d66beb3ed0df977246a02a9c46de4e05d7c0264bcde53b6b7f',
'com.mikepenz.iconics:meteocons-typeface:39a8a9e70cd8287cdb119af57a672a41dd09240dba6697f5a0dbda1ccc33298b',
- 'com.mikepenz.iconics:octicons-typeface:67ed7d456a9ce5f5307b85f955797bfb3dd674e2f6defb31c6b8bbe2ede290be',
+ 'com.squareup.okhttp:okhttp:1cc716e29539adcda677949508162796daffedb4794cbf947a6f65e696f0381c',
'com.nispok:snackbar:46b5eb9d630d329e13c2ce00ee9fb115ffb66c23c72cff32ee97eedd76824c6f',
- 'com.mikepenz.iconics:community-material-typeface:f1c5afee5f0f10d66beb3ed0df977246a02a9c46de4e05d7c0264bcde53b6b7f',
- 'com.squareup.okhttp:okhttp:bc0da7ac1f5441619faa2082811938acf7df97e4a8e08f0e043ff4937414d5ad',
-// 'OpenKeychain.extern.openkeychain-api-lib:openkeychain-intents:111d7d53b9e920ad3405f8f3eb0ab7bd3aee66d577442452754b83c7c1c1d49a',
-// 'OpenKeychain.extern.openpgp-api-lib:openpgp-api:544b7b2e20955556b83d1b72763543aa789836ebc1e77b332ed7cd83ef765c4a',
-// 'com.madgag.spongycastle:core:97276487be598747ba78c063c90cea7fc3c7ad9bc7aeba03c0b9c98692052b8a',
-// 'com.madgag.spongycastle:pkix:979aa4b2aaef94866e0f97b05b1922244eaf8b650f3691a3c44760ff0a41562b',
-// 'com.madgag.spongycastle:pg:da319de706d946f178140959c74aec126f7803f1104dbad89bb1f55a53f6e1a9',
-// 'OpenKeychain.extern:minidns:8274d50124d9584e95df0c5da7798269ac9caf0eab560df929c2c658ca624037',
-// 'com.madgag.spongycastle:prov:902a484219bbf4e395a1c32da65b2453133e195bcc92336dc8c33b7c58edcd60',
+ 'org.apache.james:apache-mime4j-core:4d7434c68f94b81a253c12f28e6bbb4d6239c361d6086a46e22e594bb43ac660',
+ 'com.squareup.okhttp:okhttp-urlconnection:79ec6f4e79e683105e87fe83278a531c693e538d30e3b9237000ce7c94fcb2cf',
+ 'org.thoughtcrime.ssl.pinning:AndroidPinning:afa1d74e699257fa75cb109ff29bac50726ef269c6e306bdeffe8223cee06ef4',
+ 'org.apache.james:apache-mime4j-dom:7e6b06ee164a1c21b7e477249ea0b74a18fddce44764e5764085f58dd8c34633',
+// 'OpenKeychain.extern.openpgp-api-lib:openpgp-api:a3f8b2ed40aaf12169e2a4e1f25e3764aa5ccb430683e1e7ca7867471eaf2bba',
+ 'com.cocosw:bottomsheet:871f5f4d6c10936569caf3528271efd77594a67aa5511765c96d7096c9b05f96',
+// 'OpenKeychain.extern.spongycastle:core:6006a83fa427f4e5c8c93458176ab5e3b54d8dba7942171cb76cb134fc574c58',
+// 'OpenKeychain.extern.openkeychain-api-lib:openkeychain-intents:8582442aa26e13c5a4bdf3588a22cb94b2fa5de6c79b84244fb575aa401fc330',
+// 'OpenKeychain.extern.spongycastle:pg:0fd64a60311c5557f230bec9b2b162c9e6e690ccc83ac6b5af6a8d616309da98',
+// 'OpenKeychain.extern.spongycastle:pkix:2348474aa27cb0461a368191d4d8fe7479a212b6365b177da131f4efa4c57f24',
+// 'OpenKeychain.extern.spongycastle:prov:85c9ed6e24c5c7e5f7ff7c22d367bb553d020693350bd1c75555e6895311bb69',
+// 'OpenKeychain.extern.safeslinger-exchange:safeslinger-exchange:274b71f8a1c383fb506342fd0f614b4a0cdb25517b5b2a1dfef9a4a2575477ed',
'com.android.support:support-annotations:beac5cae60bdb597df9af9c916f785c2f71f8c8ae4be9a32d4298dea85496a42',
-// 'OpenKeychain.extern.KeybaseLib:Lib:d52e7888cea6de9e077501bb533270b2a86b52cb8af49e5f44ee8c4bb19ea017',
-// 'OpenKeychain.extern.safeslinger-exchange:safeslinger-exchange:76e5da6b4f5f8835b12649e17569f0d0d8d89552815a61383c128545632689d1',
- 'com.squareup.okio:okio:b53c1760864e1c39b5275d9023e2a6fbe8f3189e6e67b4c87877b8ec8f92e05a',
+// 'OpenKeychain.extern:minidns:25e351fa4145e2a9b0a76658c48619b307f71432db7492e9e8a6b34aa2e9bdcf',
+// 'OpenKeychain.extern.KeybaseLib:Lib:79c78c1054b58200028211e21f2c89012dc4a1eafdb00cc99a5ce1f61ad16937',
+ 'com.squareup.okio:okio:114bdc1f47338a68bcbc95abf2f5cdc72beeec91812f2fcd7b521c1937876266',
]
}
+
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml
index 1ef8b2eb3..11e86b28b 100644
--- a/OpenKeychain/src/main/AndroidManifest.xml
+++ b/OpenKeychain/src/main/AndroidManifest.xml
@@ -263,9 +263,7 @@
<action android:name="org.sufficientlysecure.keychain.action.DECRYPT_DATA" />
<category android:name="android.intent.category.DEFAULT" />
-
- <data android:scheme="file" />
- <data android:scheme="content" />
+ <data android:mimeType="*/*" />
</intent-filter>
<!-- DECRYPT_TEXT -->
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/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
index 311ef2d3b..ebd48b9a5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
@@ -91,14 +91,16 @@ 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);
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..b6ec7234e
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/BitInputStream.java
@@ -0,0 +1,125 @@
+/*
+ * 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 sream, 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)
+ throws IOException {
+ int value = 0;
+ for (int i = aNumberOfBits - 1; i >= 0; i--) {
+ value |= (readBit() << 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() throws IOException {
+ if (iIs == null)
+ throw new IOException("Already closed");
+
+ if (iNextBit == 8) {
+ iBuffer = iIs.read();
+
+ if (iBuffer == -1)
+ 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..ead70b8f6
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/experimental/SentenceConfirm.java
@@ -0,0 +1,206 @@
+/*
+ * 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");
+ int bits = bin.readBits(neededBits);
+ 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() != 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() != 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() != 0) {
+ sentence.append(" ").append(getWord(adv, bits)); // Adverb
+ }
+
+ sentence.incBits();
+ if (bits.readBit() != 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..4e68e76c5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java
@@ -77,7 +77,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..7473705f3 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;
@@ -196,19 +197,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);
@@ -228,7 +233,7 @@ public class HkpKeyserver extends Keyserver {
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,17 +243,12 @@ 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 == null ? "" : " 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,
@@ -299,30 +299,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 +356,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);
@@ -363,11 +383,14 @@ public class HkpKeyserver extends Keyserver {
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
@@ -418,7 +441,7 @@ public class HkpKeyserver extends Keyserver {
* Tries to find a server responsible for a given domain
*
* @return A responsible Keyserver or null if not found.
- * TODO: PHILIP Add proxy functionality
+ * TODO: Add proxy functionality
*/
public static HkpKeyserver resolve(String domain) {
try {
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..486d658f6 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;
@@ -49,7 +50,9 @@ public class KeybaseKeyserver extends Keyserver {
mQuery = query;
try {
- Iterable<Match> matches = Search.search(query, proxy);
+ KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient());
+ keybaseQuery.setProxy(proxy);
+ Iterable<Match> matches = keybaseQuery.search(query);
for (Match match : matches) {
results.add(makeEntry(match));
}
@@ -101,7 +104,9 @@ public class KeybaseKeyserver extends Keyserver {
@Override
public String get(String id, Proxy proxy) throws QueryFailedException {
try {
- return User.keyForUsername(id, proxy);
+ KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient());
+ keybaseQuery.setProxy(proxy);
+ return User.keyForUsername(keybaseQuery, id);
} catch (KeybaseException e) {
throw new QueryFailedException(e.getMessage());
}
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..15e0d94e9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
@@ -62,15 +62,15 @@ 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, Proxy proxy)
+ throws QueryFailedException, QueryNeedsRepairException;
public abstract String get(String keyIdHex, Proxy proxy) throws QueryFailedException;
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 d9e48af8a..7ec33874f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java
@@ -28,6 +28,7 @@ import java.util.ArrayList;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull;
+import android.text.TextUtils;
import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.codec.DecodeMonitor;
@@ -86,6 +87,11 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> {
DecryptVerifyResult decryptResult = null;
PgpDecryptVerifyInputParcel decryptInput = input.getDecryptInput();
+
+ if (!input.getMimeDecode() && decryptInput == null) {
+ throw new AssertionError("no decryption or mime decoding, this is probably a bug");
+ }
+
if (decryptInput != null) {
log.add(LogType.MSG_DATA_OPENPGP, 1);
@@ -109,16 +115,33 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> {
return new InputDataResult(InputDataResult.RESULT_ERROR, log);
}
+ // inform the storage provider about the mime type for this uri
+ if (decryptResult.getDecryptionMetadata() != null) {
+ TemporaryStorageProvider.setMimeType(mContext, currentInputUri,
+ decryptResult.getDecryptionMetadata().getMimeType());
+ }
+
} else {
currentInputUri = input.getInputUri();
}
- // If we aren't supposed to attempt mime decode, we are done here
- if (!input.getMimeDecode()) {
-
- if (decryptInput == null) {
- throw new AssertionError("no decryption or mime decoding, this is probably a bug");
+ // 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) {
+ OpenPgpMetadata metadata = decryptResult.getDecryptionMetadata();
+ String fileName = metadata.getFilename();
+ String contentType = metadata.getMimeType();
+ if (!TextUtils.isEmpty(fileName)
+ || contentType != null
+ && !contentType.startsWith("multipart/")
+ && !contentType.startsWith("text/")
+ && !contentType.startsWith("application/")) {
+ skipMimeParsing = true;
}
+ }
+
+ // If we aren't supposed to attempt mime decode after decryption, we are done here
+ if (skipMimeParsing || !input.getMimeDecode()) {
log.add(LogType.MSG_DATA_SKIP_MIME, 1);
@@ -309,25 +332,32 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> {
log.add(LogType.MSG_DATA_MIME, 1);
- // open current uri for input
- InputStream in = mContext.getContentResolver().openInputStream(currentInputUri);
- parser.parse(in);
+ try {
- if (mSignedDataUri != null) {
+ // open current uri for input
+ InputStream in = mContext.getContentResolver().openInputStream(currentInputUri);
+ parser.parse(in);
- if (decryptResult != null) {
- decryptResult.setSignatureResult(mSignedDataResult.getSignatureResult());
- } else {
- decryptResult = mSignedDataResult;
- }
+ if (mSignedDataUri != null) {
- // the actual content is the signed data now (and will be passed verbatim, if parsing fails)
- currentInputUri = mSignedDataUri;
- in = mContext.getContentResolver().openInputStream(currentInputUri);
- // reset signed data result, to indicate to the parser that it is in the inner part
- mSignedDataResult = null;
- parser.parse(in);
+ if (decryptResult != null) {
+ decryptResult.setSignatureResult(mSignedDataResult.getSignatureResult());
+ } else {
+ decryptResult = mSignedDataResult;
+ }
+ // the actual content is the signed data now (and will be passed verbatim, if parsing fails)
+ currentInputUri = mSignedDataUri;
+ in = mContext.getContentResolver().openInputStream(currentInputUri);
+ // reset signed data result, to indicate to the parser that it is in the inner part
+ mSignedDataResult = null;
+ parser.parse(in);
+
+ }
+ } catch (MimeException e) {
+ // a mime error likely means that this wasn't mime data, after all
+ e.printStackTrace();
+ log.add(LogType.MSG_DATA_MIME_BAD, 2);
}
// if we found data, return success
@@ -363,10 +393,6 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> {
e.printStackTrace();
log.add(LogType.MSG_DATA_ERROR_IO, 2);
return new InputDataResult(InputDataResult.RESULT_ERROR, log);
- } catch (MimeException e) {
- e.printStackTrace();
- log.add(LogType.MSG_DATA_MIME_ERROR, 2);
- return new InputDataResult(InputDataResult.RESULT_ERROR, log);
}
}
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..aaff0a07c 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);
}
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 6ac34faa2..fc72a9ac2 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),
@@ -832,7 +833,7 @@ public abstract class OperationResult implements Parcelable {
MSG_DATA_DETACHED_NESTED(LogLevel.WARN, R.string.msg_data_detached_nested),
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_ERROR (LogLevel.ERROR, R.string.msg_data_mime_error),
+ MSG_DATA_MIME_BAD(LogLevel.INFO, R.string.msg_data_mime_bad),
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),
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..36b4f5e1e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
@@ -52,13 +52,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;
@@ -512,8 +512,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
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 5acf6dd41..c8cdbd59d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java
@@ -456,11 +456,15 @@ public class UncachedKeyRing {
// 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() > 100) {
+ 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..0f90f8141 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 = 13;
static Boolean apgHack = false;
private Context mContext;
@@ -296,6 +296,8 @@ public class KeychainDatabase extends SQLiteOpenHelper {
// the api_accounts fix and the new update keys table
return;
}
+ case 13:
+ // do nothing here, just consolidate
}
@@ -306,6 +308,13 @@ public class KeychainDatabase extends SQLiteOpenHelper {
mContext.getApplicationContext().startActivity(consolidateIntent);
}
+ @Override
+ public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // 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/ui/CertifyFingerprintFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java
index 552fa34c0..2409523bc 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,16 @@ 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, 16);
+ } catch (IOException ioe) {
+ fingerprint = "-";
+ }
- 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/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
index 5eb9963f5..4e9a6f17d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
@@ -168,7 +168,7 @@ public class DecryptActivity extends BaseActivity {
return;
}
- uris.add(intent.getData());
+ uris.add(uri);
}
}
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..a0650f8b1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java
@@ -257,7 +257,6 @@ 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();
@@ -266,8 +265,8 @@ public class DecryptListFragment
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);
+ FileHelper.saveDocument(this, filename, metadata.getMimeType(),
+ REQUEST_CODE_OUTPUT);
}
private void saveFile(Uri saveUri) {
@@ -376,10 +375,12 @@ public class DecryptListFragment
// 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, "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);
@@ -445,6 +446,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;
}
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..0e357cfcd 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java
@@ -18,6 +18,7 @@
package org.sufficientlysecure.keychain.ui;
+import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
@@ -224,9 +225,8 @@ 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;
@@ -441,9 +452,29 @@ public class EncryptFilesFragment
}
- // prepares mOutputUris, either directly and returns false, or indirectly
- // which returns true and will call cryptoOperation after mOutputUris has
- // been set at a later point.
+ /**
+ * Checks that the input uris are not linked to our own internal storage.
+ * This prevents the encryption of our own database (-> export of whole database)
+ */
+ private void securityCheckInternalStorage() {
+ for (FilesAdapter.ViewModel model : mFilesAdapter.mDataset) {
+ File fileInput = new File(model.inputUri.getPath());
+ try {
+ // the canonical path of the file must not start with /data/data/org.sufficientlysecure.keychain/
+ if (fileInput.getCanonicalPath().startsWith(getActivity().getApplicationInfo().dataDir)) {
+ throw new RuntimeException("Encrypting OpenKeychain's private files is not allowed!");
+ }
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "Getting canonical path failed!", e);
+ }
+ }
+ }
+
+ /**
+ * Prepares mOutputUris, either directly and returns false, or indirectly
+ * which returns true and will call cryptoOperation after mOutputUris has
+ * been set at a later point.
+ */
private boolean prepareOutputStreams() {
switch (mAfterEncryptAction) {
@@ -519,6 +550,8 @@ public class EncryptFilesFragment
}
+ securityCheckInternalStorage();
+
return actionsParcel;
}
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/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
index 4a46896bc..6331aa384 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
@@ -107,7 +107,7 @@ 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 vKeySaveButton = 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);
@@ -133,7 +133,11 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
share(false, false);
}
});
- vKeySafeButton.setOnClickListener(new View.OnClickListener() {
+ // Show save only on Android >= 4.4 (Document Provider)
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ vKeySaveButton.setVisibility(View.GONE);
+ }
+ vKeySaveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
exportToFile();
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/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/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/linked/LinkedIdCreateHttpsStep2Fragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateHttpsStep2Fragment.java
index 22a201ba3..44323543f 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,9 +132,10 @@ public class LinkedIdCreateHttpsStep2Fragment extends LinkedIdCreateFinalFragmen
String targetName = "pgpkey.txt";
+ // TODO: not supported on Android < 4.4
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,
+ targetName,
+ "text/plain",
REQUEST_CODE_OUTPUT);
}
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..9a6d33260 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java
@@ -103,8 +103,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
index 2e0b0af36..cc90c173f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java
@@ -69,13 +69,14 @@ public class ExportHelper
: 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: for valodim
+// 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
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..fea3e65b6 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FileHelper.java
@@ -18,7 +18,6 @@
package org.sufficientlysecure.keychain.util;
import android.annotation.TargetApi;
-import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Context;
@@ -30,20 +29,13 @@ 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;
@@ -82,52 +74,26 @@ 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 {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
openDocumentKitKat(fragment, mimeType, multiple, requestCode);
+ } else {
+ openDocumentPreKitKat(fragment, last, mimeType, multiple, 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);
+ public static void saveDocument(Fragment fragment, String targetName, int requestCode) {
+ saveDocument(fragment, targetName, "*/*", 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);
- } else {
+ public static void saveDocument(Fragment fragment, String targetName, String mimeType,
+ int requestCode) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
saveDocumentKitKat(fragment, mimeType, targetName, requestCode);
+ } else {
+ throw new RuntimeException("saveDocument does not support Android < 4.4!");
}
}
- 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(
@@ -172,36 +138,6 @@ public class FileHelper {
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 {
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..1040e683b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/NfcHelper.java
@@ -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..32a5406e0
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/OkHttpKeybaseClient.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.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 final OkUrlFactory factory;
+
+ private static OkUrlFactory generateUrlFactory() {
+ OkHttpClient client = new OkHttpClient();
+ return new OkUrlFactory(client);
+ }
+
+ public OkHttpKeybaseClient() {
+ factory = generateUrlFactory();
+ }
+
+ @Override
+ public URLConnection openConnection(URL url) throws IOException {
+ return openConnection(url, null);
+ }
+
+ @Override
+ public URLConnection openConnection(URL url, Proxy proxy) throws IOException {
+ 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 keybase.io pinned certificate
+ 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);
+ }
+
+} \ No newline at end of file
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/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_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_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-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_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/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/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/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/key_view.xml b/OpenKeychain/src/main/res/menu/key_view.xml
index 14ea099f4..1bda1463a 100644
--- a/OpenKeychain/src/main/res/menu/key_view.xml
+++ b/OpenKeychain/src/main/res/menu/key_view.xml
@@ -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/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/values-cs/strings.xml b/OpenKeychain/src/main/res/values-cs/strings.xml
index 6b6bc956b..79a5a276c 100644
--- a/OpenKeychain/src/main/res/values-cs/strings.xml
+++ b/OpenKeychain/src/main/res/values-cs/strings.xml
@@ -135,7 +135,7 @@
<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_verify_keyserver_connection">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>
@@ -496,7 +496,7 @@
<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_connection_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>
diff --git a/OpenKeychain/src/main/res/values-de/strings.xml b/OpenKeychain/src/main/res/values-de/strings.xml
index 291ebf238..0e4a43c6f 100644
--- a/OpenKeychain/src/main/res/values-de/strings.xml
+++ b/OpenKeychain/src/main/res/values-de/strings.xml
@@ -155,7 +155,7 @@
<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_verify_keyserver_connection">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>
@@ -386,7 +386,7 @@
<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_verifying_keyserver_connection">Schlüsselserver wird verifiziert…</string>
<string name="progress_starting_orbot">Orbot wird gestartet…</string>
<!--action strings-->
<string name="hint_cloud_search_hint">Via Name, E-Mail suchen...</string>
@@ -691,7 +691,7 @@
<!--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_connection_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>
diff --git a/OpenKeychain/src/main/res/values-es/strings.xml b/OpenKeychain/src/main/res/values-es/strings.xml
index 043918c64..a6849c542 100644
--- a/OpenKeychain/src/main/res/values-es/strings.xml
+++ b/OpenKeychain/src/main/res/values-es/strings.xml
@@ -155,7 +155,7 @@
<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_verify_keyserver_connection">Verificar servidor de claves</string>
<string name="label_enter_keyserver_url">Introduzca URL de servidor de claves</string>
<string name="label_keyserver_dialog_delete">Borrar servidor de claves</string>
<string name="label_theme">Tema decorativo</string>
@@ -386,7 +386,7 @@
<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_verifying_keyserver_connection">verificando servidor de claves...</string>
<string name="progress_starting_orbot">Iniciando Orbot...</string>
<!--action strings-->
<string name="hint_cloud_search_hint">Buscar mediante Nombre, Correo electrónico...</string>
@@ -691,7 +691,7 @@
<!--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_connection_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>
diff --git a/OpenKeychain/src/main/res/values-eu/strings.xml b/OpenKeychain/src/main/res/values-eu/strings.xml
index de4fb68d6..f57297498 100644
--- a/OpenKeychain/src/main/res/values-eu/strings.xml
+++ b/OpenKeychain/src/main/res/values-eu/strings.xml
@@ -154,7 +154,7 @@
<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_verify_keyserver_connection">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>
@@ -376,7 +376,7 @@
<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_verifying_keyserver_connection">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>
@@ -675,7 +675,7 @@
<!--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_connection_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>
diff --git a/OpenKeychain/src/main/res/values-fa/strings.xml b/OpenKeychain/src/main/res/values-fa/strings.xml
index 86d8ab5cd..790d5e90c 100644
--- a/OpenKeychain/src/main/res/values-fa/strings.xml
+++ b/OpenKeychain/src/main/res/values-fa/strings.xml
@@ -146,7 +146,7 @@
<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_verify_keyserver_connection">بررسی سرورِ کلیدها</string>
<string name="label_enter_keyserver_url">آدرس URL سرورِ کلید را وارد کنید</string>
<string name="label_keyserver_dialog_delete">حذف سرورهای کلید</string>
<string name="label_theme">قالب</string>
diff --git a/OpenKeychain/src/main/res/values-fr/strings.xml b/OpenKeychain/src/main/res/values-fr/strings.xml
index 4a6c2bbfe..b5e5f3d53 100644
--- a/OpenKeychain/src/main/res/values-fr/strings.xml
+++ b/OpenKeychain/src/main/res/values-fr/strings.xml
@@ -155,7 +155,7 @@
<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_verify_keyserver_connection">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>
@@ -386,7 +386,7 @@
<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_verifying_keyserver_connection">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>
@@ -691,7 +691,7 @@
<!--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_connection_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>
diff --git a/OpenKeychain/src/main/res/values-it/strings.xml b/OpenKeychain/src/main/res/values-it/strings.xml
index 9f58dc3ba..5b87c6ced 100644
--- a/OpenKeychain/src/main/res/values-it/strings.xml
+++ b/OpenKeychain/src/main/res/values-it/strings.xml
@@ -149,7 +149,7 @@
<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_verify_keyserver_connection">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>
diff --git a/OpenKeychain/src/main/res/values-ja/strings.xml b/OpenKeychain/src/main/res/values-ja/strings.xml
index 6f735b35b..789a35e75 100644
--- a/OpenKeychain/src/main/res/values-ja/strings.xml
+++ b/OpenKeychain/src/main/res/values-ja/strings.xml
@@ -155,7 +155,7 @@
<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_verify_keyserver_connection">鍵サーバを検証</string>
<string name="label_enter_keyserver_url">鍵サーバのURLを入力</string>
<string name="label_keyserver_dialog_delete">鍵サーバの削除</string>
<string name="label_theme">テーマ</string>
@@ -382,7 +382,7 @@
<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>
@@ -674,7 +674,7 @@
<!--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>
diff --git a/OpenKeychain/src/main/res/values-nl/strings.xml b/OpenKeychain/src/main/res/values-nl/strings.xml
index 1a02fdc07..812376026 100644
--- a/OpenKeychain/src/main/res/values-nl/strings.xml
+++ b/OpenKeychain/src/main/res/values-nl/strings.xml
@@ -151,7 +151,7 @@
<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_verify_keyserver_connection">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>
@@ -366,7 +366,7 @@
<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>
+ <string name="progress_verifying_keyserver_connection">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-->
@@ -648,7 +648,7 @@
<!--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_connection_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>
diff --git a/OpenKeychain/src/main/res/values-ru/strings.xml b/OpenKeychain/src/main/res/values-ru/strings.xml
index 55a5afa5e..6b73d367c 100644
--- a/OpenKeychain/src/main/res/values-ru/strings.xml
+++ b/OpenKeychain/src/main/res/values-ru/strings.xml
@@ -152,7 +152,7 @@
<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_verify_keyserver_connection">Подтвердить сервер ключей</string>
<string name="label_enter_keyserver_url">Введите адрес сервера ключей</string>
<string name="label_keyserver_dialog_delete">Удалить сервер ключей</string>
<string name="label_theme">Тема</string>
@@ -364,7 +364,7 @@
<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>
<!--action strings-->
<string name="hint_cloud_search_hint">Искать через Имя, Email...</string>
<!--key bit length selections-->
@@ -568,7 +568,7 @@
<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_connection_verified">Сервер ключей подтверждён!</string>
<string name="add_keyserver_without_verification">Сервер ключей добавлен без подтверждения.</string>
<string name="add_keyserver_invalid_url">Неправильный адрес!</string>
<!--Navigation Drawer-->
diff --git a/OpenKeychain/src/main/res/values-sr/strings.xml b/OpenKeychain/src/main/res/values-sr/strings.xml
index 5c6d03950..ed7bce5f7 100644
--- a/OpenKeychain/src/main/res/values-sr/strings.xml
+++ b/OpenKeychain/src/main/res/values-sr/strings.xml
@@ -155,7 +155,7 @@
<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_verify_keyserver_connection">Овери сервер кључева</string>
<string name="label_enter_keyserver_url">Унесите УРЛ сервера кључева</string>
<string name="label_keyserver_dialog_delete">Обриши сервер кључева</string>
<string name="label_theme">Тема</string>
@@ -390,7 +390,7 @@
<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">Покрећем Орбот…</string>
<!--action strings-->
<string name="hint_cloud_search_hint">Тражи преко имена, е-адресе…</string>
@@ -709,7 +709,7 @@
<!--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">Неисправан УРЛ!</string>
<string name="add_keyserver_connection_failed">Неуспех повезивања са сервером кључева. Проверите УРЛ и вашу везу са интернетом.</string>
diff --git a/OpenKeychain/src/main/res/values-sv/strings.xml b/OpenKeychain/src/main/res/values-sv/strings.xml
index 1ccac9199..4a0a9d083 100644
--- a/OpenKeychain/src/main/res/values-sv/strings.xml
+++ b/OpenKeychain/src/main/res/values-sv/strings.xml
@@ -135,7 +135,7 @@
<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_verify_keyserver_connection">Verifiera nyckelserver</string>
<string name="label_enter_keyserver_url">Ange nyckelserver-URL</string>
<string name="pref_keyserver">OpenPGP nyckelservrar</string>
<string name="pref_keyserver_summary">Sök nycklar på valda OpenPGP nyckelservrar (HKP-protokollet)</string>
@@ -313,7 +313,7 @@
<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_verifying_keyserver_connection">verifierar nyckelserver...</string>
<!--action strings-->
<string name="hint_cloud_search_hint">Söker via Namn, E-post...</string>
<!--key bit length selections-->
@@ -565,7 +565,7 @@
<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_connection_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>
diff --git a/OpenKeychain/src/main/res/values-zh-rTW/strings.xml b/OpenKeychain/src/main/res/values-zh-rTW/strings.xml
index 74d1cd781..87144422d 100644
--- a/OpenKeychain/src/main/res/values-zh-rTW/strings.xml
+++ b/OpenKeychain/src/main/res/values-zh-rTW/strings.xml
@@ -149,7 +149,7 @@
<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_verify_keyserver_connection">驗證金鑰伺服器</string>
<string name="label_enter_keyserver_url">輸入金鑰伺服器網址</string>
<string name="label_keyserver_dialog_delete">刪除金鑰伺服器</string>
<string name="label_theme">主題</string>
@@ -362,7 +362,7 @@
<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_verifying_keyserver_connection">正在驗證金鑰伺服器...</string>
<string name="progress_starting_orbot">正在啟動Orbot...</string>
<!--action strings-->
<string name="hint_cloud_search_hint">使用姓名,電子郵件尋找...</string>
@@ -625,7 +625,7 @@
<!--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">連線到金鑰伺服器失敗。請確認金鑰伺服器網址及網路連線。</string>
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index aa25b2aa7..360ecb136 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -63,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>
@@ -84,12 +85,14 @@
<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_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>
@@ -100,6 +103,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>
<!-- menu -->
<string name="menu_preferences">"Settings"</string>
@@ -116,7 +120,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>
@@ -173,8 +177,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>
@@ -195,8 +200,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>
@@ -446,7 +451,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>
@@ -779,9 +784,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>
@@ -990,6 +996,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>
@@ -1362,7 +1369,7 @@
<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_error">"Error parsing MIME 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_length">"Content-Length: %s"</string>
<string name="msg_data_mime">"Parsing MIME data structure"</string>
@@ -1441,9 +1448,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>
diff --git a/README.md b/README.md
index c6eac8fe3..e06366571 100644
--- a/README.md
+++ b/README.md
@@ -46,7 +46,7 @@ Expand the Tools directory and select "Android SDK Build-tools (Version 21.1.2)"
Expand the Extras directory and install "Android Support Repository"
Select everything for the newest SDK Platform, API 22, and also API 21
5. Export ANDROID_HOME pointing to your Android SDK
-6. Execute ``./gradlew build``
+6. Execute ``./gradlew assembleDebug``
7. You can install the app with ``adb install -r OpenKeychain/build/outputs/apk/OpenKeychain-debug-unaligned.apk``
### Run Tests
diff --git a/extern/KeybaseLib b/extern/KeybaseLib
-Subproject 0b0a60533c5f76b60e43895f3a0342bb0be6853
+Subproject b89648f50011445df59fa02f16a0691857aea68