Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 106 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,90 +2,168 @@

Provides framework / prototype for end-to-end encryption with perfect forward secrecy in Java

Protocol combines symmetric and asymmetric encryption algorithms [RSA, Elliptic curve Diffie–Hellman, AES] to implement end-to-end encryption, It works on top of https
Protocol combines symmetric and asymmetric encryption algorithms [RSA, Elliptic Curve Diffie–Hellman, AES] to implement end-to-end encryption. It works on top of https protocol providing encryption in transport and storage

protocol provides encryption in transport and storage
## Getting Started
Dependencies are managed using [Maven](https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html).

The framework uses Bouncy Castle as provider for encryption. The dependency has to be excluded from the *fat* jar because of signature verification problems.

From the source: [tomee.apache](http://tomee.apache.org/bouncy-castle.html), bouncy castle is easily installed in two steps:
1. Add the Bouncy Castle provider jar to the $JAVA_HOME/jre/lib/ext directory
2. Create a Bouncy Castle provider entry in the $JAVA_HOME/jre/lib/security/java.security file

The entry to java.security will look something like the following:

> security.provider.N=org.bouncycastle.jce.provider.BouncyCastleProvider

The framework is configured to work with a mysql database. It uses the mysql-connector-v8 which may or may not be compatible with older versions on MySQL. The following line in `DataBaseServiceImpl.java` can be changed for other database usage.
> dataSource.setUrl("jdbc:mysql://" + config.getString("sql.host") + "/" + config.getString("sql.database"));

There is a schema.sql file located in the SQL directory of the otr-server. A database should be created and initialized to use this schema.

[Lithium Flow](https://github.com/lithiumtech/flow) is used for managing configuration files. The config file must be specified at runtime with a system property, and the library is included in the pom.xml.

### Configuration
There are three total configuration files, a common, server, and client. The server and client contain some required configurations for starting the application.

#### Server
The following items need to be configured before the server will work:
1. `sql.host` - include the hostname, default port used is 4567
2. `sql.user` - username of sql database
3. `sql.password` - password of sql database
4. `sql.database` - database name used when creating the sql schema mentioned above

#### Client
The following items to need to be configured before the client will work:
1. `server.url` - default port number is 4567
2. `user.keystore` - storage location for key information generated for a user

The ECDH curve can also be changed in this configuration file.

### Running
After ensuring that all of the dependencies and configurations have been taken care of, build the application with `mvn package` from the top-level directory.

Change into the server's directory and run the server with:
> java -Dconfig=server.config -cp target/*-fat.jar com.jigar.otr.OTRServerMain

Start another shell and change into the client's directory, run the client with:
> java -Dconfig=client.config -cp target/*-fat.jar com.jigar.otr.OTRClientDemoMain

Sample exchange on the same client.

User1
1. Register user1
2. Login as user1
3. Logout of the user (writes login information to disk)

User2
1. Register user2
2. Login as user2
3. Logout of the user (writes login information to disk)

- Login as user1, and list users.
- Send a message to user2 using the id identified by the list user's call, logout.
- Login to user2, receive the message.

## API
### Keys

A set of keys are generated on the client-side before interaction with the server.

##### Identity Key
During registration, client generates RSA 4096 bit key pair, public key gets sent to server during registration, private key remains at client
During registration, client generates a 4096 bit RSA key pair, and sends the public key to server. The private key remains at client.

##### Pre-Keys
During registration client generates large bulk of ECDH key pairs, and public portion of these keys gets sent to server during registration, all private keys remains at client
During registration, client generates large bulk of ECDH key pairs (configurable), and the public portion of these keys is sent to server. All private keys remains at client to be used as keys for encrypting communication.

### Encryption
It uses 256 bit AES encryption
Current implementation uses 256 bit AES Encryption.

### Protocol

##### registration
#### Registration

- User provides `login`, `password`, `public identity key`, `set of public pre-keys` -> server returns user identification number back upon successful registration, client stores this information

#### Login

- User provides `login`, `password`, `public identity key`, `set of public pre-keys`, user gets user identification number back upon successful registration, which is stored
- User provides `login`, `password` and `signedLogin` (signed login with private identity key) -> server provides `userId` (user identification number) on a successful login.

##### login
#### Logout [TODO Encrypt Stored Information]

- User provides `login`, `password` and `signedLogin` (signed login with private identity key), upon login server provides `userId` (user identification number) which client stores it
- User writes all key related information to the file "username-otr.json" in the directory defined by the "user.keystore" configuration variable. The user's information is then cleared from memory. The information is stored as plaintext.

#### List Users

##### send message
- User request a list of users from the server.

- Server returns a list of user's with including both their userId and userName.

#### Send Message

- Bob wants to send message to Alice, Both user needs to have registered in system already, Bob will request Alice's public identity key & Alice's one of the public pre-key from server server
- Bob wants to send message to Alice -- Both users need to be registered in system already

- Bob will request Alice's public identity key & one of her public pre-keys being stored on the server

- Server will give public identity key and one of the public pre-key of Alice to Bob
- Server returns public identity key and one of the Alice's public pre-keys of to Bob

- Server will remove supplied public pre-key, if there is only one last public pre-key left on server, server will keep it until client comes back and replenishes them
- Server will remove supplied public pre-key; if this is Alice's last public pre-key on server, the server will keep it until Alice comes back and replenishes them

- Bob generates ECDH key pair and using Alice's ECDH public pre-key derives secret

- Bob generates random salt and IV

- Bob uses computed secret, salt and IV as input to AES (256 bit) to encrypt his message for Alice

- Bob uses Alice's public identity key to encrypt Bob's ECDH public pre-key, salt and Alice's public ECDH pre-key
- Bob uses Alice's public identity key to encrypt Bob's ECDH public pre-key, salt, IV, and Alice's public ECDH pre-key

- Bob signs salt with his private key

- Bob sends server Alice's userId, encrypted message, encrypted salt, signed salt, encrypted IV, encrypted Alice's public ECDH pre-key, encrypted Bob's public ECDH pre-key and signed salt
- Bob sends server Alice's userId, encrypted message, encrypted salt, signed salt, encrypted IV, Alice's public ECDH pre-key encrypted, Bob's public ECDH pre-key encrypted and signed salt

- server simply stores all these information
- Server stores all of this information

##### receive message
#### Receive Message

- Alice requests for her message to server by providing her userId, server validates if Alice is logged in
- Alice makes a request for her messages to server by providing her userId, server validates if Alice is logged in

- Server provides encrypted data which was submitted by Bob

- Alice uses her private key to decrypt Alice's ECDH public pre-key, Bob's ECDH public key, salt and IV

- Alice verifies signedSalt with Bob's public key
- Alice verifies the signed salt with Bob's public key

- Alice checks Bob's identity finger print and makes sure, Bob is really the one who Alice thinks by making sure his identity by going out of band
- Alice checks Bob's identity fingerprint to make sure Bob is really the who Alice thinks by making sure his identity by going out of band

- Alice then uses her ECDH private key, Bob's ECDH public key to compute secret and uses AES to decrypt message
- Alice then uses her ECDH private key and Bob's ECDH public key to compute secret.

##### replenishing pre-keys
- AES is used to decrypt message

#### Replenishing Pre-Keys

A user that has registered with the server has a public pre-key removed each time a user sends them a message. Because of this, the pre-keys must be replenished on the server's side.

- Client maintains N number of pre-keys on server and periodically replenishes them


### Data storage [TODO]

- To store backup of Bob and Alice's chat
- Stores backup of Bob and Alice's chat

- Alice and Bob both are asked if you want to store messages, if both agrees to continue then client proceeds with backup
- Alice and Bob both are asked if you want to store messages, if both agree to continue the client proceeds with backup

- To backup Alice's client generates a secure random key and encrypts with Bob's public key & Alice's public key and sends it to server [2 keys]
- To backup, Alice's client generates a secure random key and encrypts with both Bob's public key & Alice's public key; it is then sent to server [2 keys]

- Bob's client does the same

- Server once receives both the encrypted keys, generates a random salt and keeps on the record and provides that random salt to Bob and Alice on their next ping to server in encrypted form via their public identity keys
- Once the server receives both the encrypted keys, it generates a random salt and keeps this on record, providing the random salt to Bob and Alice on their next ping to server in encrypted form via their public identity keys

- Bob and Alice gets the secret key for their chat storage through server and decrypts with their private key and combines them to derive secret key that only Alice and Bob knows and then sends data back to server
- Bob and Alice get the secret key for their chat storage through the server and decrypt it with their private keys, combining them to derive a secret key that only Alice and Bob know. They then send data back to server

- These keys must remain present to client at all times protected by a master password which remains in the mind of user for backup and retrieval purpose



### License
Copyright 2016 Jigar Joshi

Expand Down
9 changes: 1 addition & 8 deletions otr-client/client.config
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@ app.name = otr-client
server.url = http://localhost:4567

keys.identity.keySize = 4096


keys.pre.count = 100


aes.keygen.algorithm = PBKDF2WithHmacSHA1
aes.key.iterations = 65536
aes.key.length = 256
Expand All @@ -17,8 +14,4 @@ aes.cipher.transformation = AES/CBC/PKCS5Padding
## org.bouncycastle.jce.ECNamedCurveTable.getNames
ecdh.curveName = prime192v1



##test purposes
user = jigar1
target = 2
user.keystore = users/
35 changes: 23 additions & 12 deletions otr-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.54</version>
<scope>provided</scope>
</dependency>
<!-- logging -->
<dependency>
Expand Down Expand Up @@ -73,25 +74,35 @@
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
<artifactSet>
<excludes>
<exclude>org.bouncycastle:*:*:*</exclude>
</excludes>
</artifactSet>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>com.jigar.otr.OTRClientDemoMain</Main-Class>
<Class-Path>. ./lib/bcprov-jdk15on-1.54.jar</Class-Path>
</manifestEntries>
</transformer>
</transformers>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>fat</shadedClassifierName>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.jigar.otr.OTRServerMain</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
Expand Down
20 changes: 17 additions & 3 deletions otr-client/src/main/java/com/jigar/otr/OTRClientDemoMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,37 @@ public static void main(String[] args) throws Exception {

private static void apiTest() throws Exception {
OTRClient client = OTRClient.get(Main.config());
String user = Main.config().getString("user");
int target = Main.config().getInt("target");
// String user = Main.config().getString("user");
while (true) {
Scanner scanner = new Scanner(System.in);
log.info("1. register");
log.info("2. login");
log.info("3. sendMessage");
log.info("4. readMessage");
log.info("5. exit");
log.info("5. list Users");
log.info("6. logout");
log.info("7. exit");

String command = scanner.nextLine();
String user = "";
switch (command) {
case "1":
log.info("enter user: ");
user = scanner.nextLine();
log.info("enter password: ");
String password = scanner.nextLine();
client.register(user, password);
break;
case "2":
log.info("enter user: ");
user = scanner.nextLine();
log.info("enter password: ");
password = scanner.nextLine();
client.login(user, password);
break;
case "3":
log.info("Enter target: ");
int target = Integer.valueOf(scanner.nextLine());
log.info("Enter message: ");
String message = scanner.nextLine();
client.sendMessage("From " + user + ", message = " + message, target);
Expand All @@ -69,6 +77,12 @@ private static void apiTest() throws Exception {
client.readMessages();
break;
case "5":
client.listUsers();
break;
case "6":
client.logout();
break;
case "7":
System.exit(0);
default:
log.error("invalid choice");
Expand Down
6 changes: 6 additions & 0 deletions otr-client/src/main/java/com/jigar/otr/service/OTRClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import com.jigar.otr.exception.OTRException;
import com.jigar.otr.service.impl.OTRRestClient;

import java.util.Map;

/**
* Created by jigar.joshi on 11/21/16.
*/
Expand All @@ -31,6 +33,8 @@ public interface OTRClient {

void login(String login, String password) throws OTRException;

void logout() throws OTRException;

void refreshMessageKeys() throws OTRException;

void readMessages();
Expand All @@ -41,6 +45,8 @@ public interface OTRClient {

String getPrePublicKey(int userId) throws OTRException;

String listUsers() throws OTRException;

static OTRClient get(Config config) {
String clientType = config.getString("otr.client", "rest");
switch (clientType) {
Expand Down
1 change: 0 additions & 1 deletion otr-client/src/main/java/com/jigar/otr/service/Storer.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ enum NameSpace {

void remove(NameSpace namespace);


static Storer get(Config config) {
String storerType = config.getString("storer.type", "memory");
switch (storerType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
public interface StorerWrapper {

int getUserId();
String getUsername();

String getPrivateIdKey();

Expand Down
Loading