KryptEY/KRYPTEY.md

113 lines
7.8 KiB
Markdown
Raw Normal View History

2023-05-14 07:04:47 -04:00
# KryptEY
KryptEY was created by [mellitopia](https://github.com/mellitopia)
and [amnesica](https://github.com/amnesica).
We implemented a stand alone android keyboard, KryptEY, which enables E2EE encryption of single
messages on any Android messenger. It is based on
the [Simple Keyboard](https://github.com/rkkr/simple-keyboard). The Android version of
the [Signal Protocol](https://mvnrepository.com/artifact/org.signal/libsignal-android) is used for
the E2EE functionality.
The keyboard provides the functionality to encrypt and decrypt messages, is independent of a
messenger app and does not require a server for the key exchange. The keyboard includes a separate
text field for entering the message that is to be encrypted. After selecting the receiver, the
message is sent to the text field of the used messenger and then sent to the chat partner as usual.
The chat partner copies the message to the clipboard, the application recognises the KryptEY message
as well as the sender and offers the option to decrypt the ciphertext message. The decrypted message
is displayed in the KryptEY text field and saved in the message history. Further, chat partners can
be created and deleted through the application and their security number can be verified by
comparing it on both end devices. Encrypted and decrypted messages are stored in a message history
for later viewing and there is a Q&A section that helps with questions about the keyboard and its
functionalities.
The elliptic curve X25519 with SHA-512 is used in the X3DH Key Agreement Protocol from the applied
Signal library. The hash function SHA-256 is used for the various chains and AES-256 with CBC (
Pkcs#7) is used for the encryption of the messages. SHA-512 is also used to generate the
fingerprint, the representation of the public key used for encryption.
## Initialization
After installing the app, the Signal Protocol is initialised on the device. For this purpose,
a `SignalProtocolAddress` consisting of a randomised UUID and an arbitrary device id is created.
Further, an identity key, two one-time prekeys and a signed prekey are created. From this
information, various stores are created to man- age the protocol: the `IdentityKeyStore`
, `PreKeyMetadataStore`, `PreKeyStore`, `SenderKeyStore`, `SessionStore`, `SignalProtcolStore`, and
the `SignedPreKeyStore`. All protocol information is stored serialised in the applications
SharedPreferences. The Jackson library is used for this purpose. All the information together forms
an account on the device, with the `SignalProtocolAddress` identifying the user.
In addition, there are four different message types in KryptEY for exchanging keys and ciphertext
messages between chat partners.
1. `PreKeyResponse`: to send the `PreKeyBundle` (Invite message)
2. `PreKeySignalMessage`: to send a ciphertext and `PreKeyBundle` after establishing the session on
ones side.
3. `SignalMessage`: to send a ciphertext
4. `PreKeyResponse`+`SignalMessage`: to send a ciphertext with new `PreKeyBundle` information to
update the session
## Session Establishment and Key Management
To exchange messages, a session must first be initialised on both end devices. If Bob wants to
communicate with Alice, Bob needs Alices `PreKeyBundle` to establish the session on his side. Alice
sends this via an invite message, which contains her `PreKeyBundle` data (`PreKeyResponse`). This
allows Bob to add Alice as a contact within the keyboard and establish a session on his side. Bob
can now send an initial encrypted message to Alice. Since Alice has not yet initialised a session
with Bob, this message is a `PreKeySignalMessage` and contains additional information besides the
actual ciphertext message so that Alice can establish a session with Bob. After Alice has also added
Bob as a contact and created a session, she can now decrypt the message Bob sent. At this point,
both parties have established a session and can send messages to each other. These messages
are `SignalMessages`.
The one-time prekeys used to establish the sessions are renewed after each use, while the identity
key is never renewed. After 30 days the signed prekeys are rotated. The old signed prekey is deleted
after 2 days. After such rotation, an updated `PreKeyBundle` is sent together with an encrypted
message with which the receiver, e.g. Bob, can update his session with Alice (`PreKeyResponse`
+`SignalMessage`). This combination of messages eliminates the need for a separate reading of the
renewed KeyBundle information. For the user, the message appears like a normal `SignalMessage`. The
session management with the manually created `PreKeyResponse` is necessary, because no server is
used for the exchange of the `PreKeyBundles`.
In addition to the `PreKeySignalMessage` and `SignalMessage`, which are also used by the Signal app,
KryptEY uses the `PreKeyResponse` and `PreKeyResponse`+`SignalMessage`. As previously mentioned,
these are necessary to guarantee the Signal Protocol without the use of a server. Further, in the
Signal app 100 one-time prekeys are created, while in KryptEY only 2 one-time prekeys are created.
These one-time prekeys are replaced after each use, which eliminates the need for time-consuming key
management of 100 one-time prekeys. Also, unlike Signal, KryptEY does not use telephone numbers to
identify users. Instead, randomised UUIDs are used. This could contribute to an increase of the
privacy of the users, since no telephone numbers are used to identify the users.tween chat partners.
## MessageEnvelope and Message Encoding
To send a message, all information is collected in a `MessageEnvelope` and then sent as plain JSON
or hidden in a decoy message. Depending on the message type, this envelope contains
the `PreKeyResponse`, the `CipherTextMessage` (`PreKeySignalMessage` or `SignalMessage`) as a byte
array, the type of the `CipherTextMessage` (`PreKeySignalMessage` or `SignalMessage`), a timestamp
and the `SignalProtocolAddress`.
There are two different encoding modes in KryptEY, raw mode and fairytale mode. Messages can be sent
as a JSON array (raw mode) or hidden in a decoy message (fairytale mode) to make the conversation
look inconspicuous. In the latter, the encrypted message is hidden in invisible, non-printable
Unicode characters. To keep the message size as small as possible, the JSON is minified, i.e. all
spaces and paragraphs are removed and the key values of the JSON are replaced by abbreviated key
values, e.g. ”preKeyResponse” becomes ”pR”. After that, the string is compressed with GZIP and
converted into a binary string. When converting to invisible Unicode characters, 4 bits are always
mapped to an invisible Unicode character like U+200C (ZERO WIDTH NON-JOINER). There are 16 invisible
Unicode characters to choose from, covering all combinations from 0000-1111. The invisible Unicode
string is then placed after an arbitrary sentence from one of the two available
fairytales [Cinderella](https://www.cs.cmu.edu/spok/grimmtmp/016.txt)
and [Rapunzel](https://www.cs.cmu.edu/spok/grimmtmp/009.txt) and can be sent to the application.
After receiving, the invisible Unicode characters are extracted from the message, converted to a
binary string, decompressed, and deminified. Then the message can be read by the app. The invisible
characters are included in the transmitted messages, which can cause problems in some messengers,
unfortunately (see Limitations in the README).
## Additional Information
The keyboard only needs the ”VIBRATE” permission to enable vibration after key press. Unlike
the [Android Open Source Project keyboard](https://android.googlesource.com/platform/packages/inputmethods/LatinIME/+/refs/heads/master/java/AndroidManifest.xml)
, the application does not require any sensitive permissions such as access to external storage or
contacts. Internet access is also not needed. At least Android 8.0 (API 26) is required and the
application has been licensed with GPL-3.0.