aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2015-09-24 14:11:20 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2015-09-24 14:11:20 +0200
commitfd80d48f5085032839aa5ddabe32eb4e7c06a1c6 (patch)
tree8789458527820e707797714d66b54e57014b5b18
parentde8eed664f32432ab214cb1a074dd28944fc3be9 (diff)
downloadopen-keychain-fd80d48f5085032839aa5ddabe32eb4e7c06a1c6.tar.gz
open-keychain-fd80d48f5085032839aa5ddabe32eb4e7c06a1c6.tar.bz2
open-keychain-fd80d48f5085032839aa5ddabe32eb4e7c06a1c6.zip
phrase confirmation
-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/ui/CertifyFingerprintFragment.java15
-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/strings.xml10
13 files changed, 1352 insertions, 11 deletions
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/ui/CertifyFingerprintFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java
index 552fa34c0..d9bc08268 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> {
@@ -180,9 +182,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/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/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index c83b598ed..2870f4d5c 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -115,7 +115,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_word">"Confirm via phrases"</string>
<string name="menu_share_log">"Share Log"</string>
<string name="menu_keyserver_add">"Add"</string>
@@ -195,8 +195,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>
@@ -1447,8 +1447,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_text">"Compare the fingerprint, character by character, with the one displayed on your partners device."</string>
+ <string name="certify_fingerprint_text_words">"Compare the phrases with the ones displayed on your partners device."</string>
<string name="certify_fingerprint_text2">"Do the fingerprints match?"</string>
<string name="label_revocation">"Revocation Reason"</string>
<string name="label_cert_type">"Type"</string>