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
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM java:8-jdk-alpine
COPY target/coding-0.0.1-SNAPSHOT-jar-with-dependencies.jar /usr/app/
WORKDIR /usr/app
ENTRYPOINT ["java", "-jar", "coding-0.0.1-SNAPSHOT-jar-with-dependencies.jar"]
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,27 @@
# coding
Project 4fun
# 3DES Encryption
3DES Encryption algorithm implementation in Java
- The application takes arguments from command line, the first argument is an encryption key, the second is text to be encrypted
- If encryption key and encryption text weren't passed from the command line, the application will try reading them from environment variables
`ENCRYPTION_KEY` `TEXT_TO_ENCRYPT`
- The application uses a 24 bit encryption key and 8 bit initialization vector
- Encryption key and initialization vector use SHA1PRNG for key generation
- DESede/CBC/PKCS5Padding is used as transformation
- Null values are not encrypted, if null used as an input for the encrypt method, the method will immediately return the null reference. The same
applies to the decrypt method

## To run the application
- Checkout the project
- `mvn package`
- `java -jar coding-0.0.1-SNAPSHOT-jar-with-dependencies.jar KEY 'text to encrypt'`

## To run the application via docker-compose
- Checkout the project
- `mvn package`
- Open the `docker-compose.yml` and set `ENCRYPTION_KEY` `TEXT_TO_ENCRYPT` environment variables
- `docker-compose up`

## To run the application via docker
- Checkout the project
- `mvn package`
- `docker build -t 3des-algorithm_encryption . `
- `docker run -it 3des-algorithm_encryption encryptionKey text`
5 changes: 5 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
3des-algorithm_encryption:
build: .
environment:
- ENCRYPTION_KEY="KDKDKDKD"
- TEXT_TO_ENCRYPT="some t3xt"
73 changes: 72 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,86 @@

<properties>
<java.version>1.8</java.version>
<hamcrest.version>2.2</hamcrest.version>
<junit-jupiter.version>5.6.2</junit-jupiter.version>
<mockito-junit-jupiter.version>2.23.0</mockito-junit-jupiter.version>
<commons-lang3.version>3.10</commons-lang3.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>

<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.6.2</version>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>${hamcrest.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito-junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<mainClass>com.verygood.security.coding.CodingApplication</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<argLine>-Dfile.encoding=UTF-8</argLine>
</configuration>
</plugin>
</plugins>
</build>

</project>
47 changes: 44 additions & 3 deletions src/main/java/com/verygood/security/coding/CodingApplication.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,49 @@
package com.verygood.security.coding;

import com.verygood.security.coding.api.Encryption;
import com.verygood.security.coding.api.IEncryptionKeyService;
import com.verygood.security.coding.api.exception.WrongInputArgumentsException;
import com.verygood.security.coding.service.EncryptionKeyServiceImpl;
import com.verygood.security.coding.service.TripleDesEncryptionImpl;
import org.apache.commons.lang3.StringUtils;

public class CodingApplication {

public static void main(String[] args) {
// TODO encrypt passed data with algorithm of your choice
}
static final String ENCRYPTION_KEY_ENV_VARIABLE = "ENCRYPTION_KEY";
static final String TEXT_TO_ENCRYPT_ENV_VARIABLE = "TEXT_TO_ENCRYPT";
private static String encryptionKey;
private static String textToEncrypt;

public static void main(String[] args) {
setArguments(args);

IEncryptionKeyService encryptionKeyService = new EncryptionKeyServiceImpl(encryptionKey);
Encryption encryptionService = new TripleDesEncryptionImpl(encryptionKeyService);
String encryptedText = encryptionService.encrypt(textToEncrypt);
String decryptedText = encryptionService.decrypt(encryptedText);

System.out.println("Encrypted text: " + encryptedText);
System.out.println("Decrypted text: " + decryptedText);
}

private static void setArguments(String[] args) {
if (args.length <= 1) {
readArgsFromEnvironmentVariables();
if (StringUtils.isAllBlank(encryptionKey, textToEncrypt)) {
throw new WrongInputArgumentsException("Arguments are empty or half empty. Please input an encryption key and a text, "
+ "e.g. ./application.jar FHDGYR 'text to encrypt'");
}
}
else {
encryptionKey = args[0];
textToEncrypt = args[1];
}
}

private static void readArgsFromEnvironmentVariables() {
String encryptionKeyFromEnv = System.getenv(ENCRYPTION_KEY_ENV_VARIABLE);
String textToEncryptFromEnv = System.getenv(TEXT_TO_ENCRYPT_ENV_VARIABLE);
encryptionKey = encryptionKeyFromEnv;
textToEncrypt = textToEncryptFromEnv;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.verygood.security.coding;
package com.verygood.security.coding.api;

public interface Encryption {
String encrypt(String text);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.verygood.security.coding.api;

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

public interface IEncryptionKeyService {
byte[] getKey() throws NoSuchAlgorithmException, InvalidKeySpecException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.verygood.security.coding.api.exception;

public class WrongInputArgumentsException extends RuntimeException {

public WrongInputArgumentsException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.verygood.security.coding.service;

import com.verygood.security.coding.api.IEncryptionKeyService;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

public class EncryptionKeyServiceImpl implements IEncryptionKeyService {

private static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";
private static final String SHA1PRNG_ALGORITHM = "SHA1PRNG";
static final int KEY_SIZE = 24;
private byte[] encryptionKeyInBytes;
private String encryptionKey;

public EncryptionKeyServiceImpl(String encryptionKey) {
this.encryptionKey = encryptionKey;
}

@Override
public byte[] getKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
if (encryptionKeyInBytes == null) {
encryptionKeyInBytes = generateKey();
}
return encryptionKeyInBytes;
}

private byte[] generateKey() throws NoSuchAlgorithmException, InvalidKeySpecException {

if (encryptionKey == null) {
System.out.println("Encryption key is blank, using an autogenerated key");
encryptionKey = "";
}

int iterations = 10;
char[] chars = encryptionKey.toCharArray();
byte[] salt = getSalt();

PBEKeySpec spec = new PBEKeySpec(chars, salt, iterations, KEY_SIZE * 8);
SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
return skf.generateSecret(spec).getEncoded();
}

private static byte[] getSalt() throws NoSuchAlgorithmException {
SecureRandom sr = SecureRandom.getInstance(SHA1PRNG_ALGORITHM);
byte[] salt = new byte[16];
sr.nextBytes(salt);
return salt;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package com.verygood.security.coding.service;

import com.verygood.security.coding.api.Encryption;
import com.verygood.security.coding.api.IEncryptionKeyService;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class TripleDesEncryptionImpl implements Encryption {

private static final Charset ENCODING = StandardCharsets.UTF_8;
private static final String ALGORITHM = "DESede";
private static final String TRANSFORMATION = ALGORITHM + "/CBC/PKCS5Padding";
private static final String SECURE_RANDOM_ALGORITHM = "SHA1PRNG";
private final IEncryptionKeyService secretKeyService;
private IvParameterSpec ivParameterSpec;
private SecretKeySpec secretKeySpecs;

public TripleDesEncryptionImpl(IEncryptionKeyService secretKeyService) {
this.secretKeyService = secretKeyService;
}

@Override
public String encrypt(String text) {
if (text == null) {
return null;
}
byte[] bytes = new byte[0];
try {
bytes = encryptDecryptInternal(text.getBytes(ENCODING), Cipher.ENCRYPT_MODE);
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | InvalidKeyException | NoSuchPaddingException
| BadPaddingException | IllegalBlockSizeException | InvalidKeySpecException e) {
e.printStackTrace();
}
return Base64.getEncoder().encodeToString(bytes);
}

@Override
public String decrypt(String text) {
if (text == null) {
return null;
}
byte[] textDecoded = Base64.getDecoder().decode(text);
byte[] bytes = new byte[0];
try {
bytes = encryptDecryptInternal(textDecoded, Cipher.DECRYPT_MODE);
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | InvalidKeyException | NoSuchPaddingException
| BadPaddingException | IllegalBlockSizeException | InvalidKeySpecException e) {
e.printStackTrace();
}
return new String(bytes, ENCODING);
}

private byte[] encryptDecryptInternal(byte[] text, int mode) throws NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException,
NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException, InvalidKeySpecException {

SecretKey key = getSecretKey();
IvParameterSpec iv = getIvParameterSpec();
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(mode, key, iv);

return cipher.doFinal(text);
}

private SecretKeySpec getSecretKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
if (secretKeySpecs == null) {
secretKeySpecs = new SecretKeySpec(secretKeyService.getKey(), ALGORITHM);
}
return secretKeySpecs;
}

private IvParameterSpec getIvParameterSpec() throws NoSuchAlgorithmException {
if (ivParameterSpec == null) {
SecureRandom randomSecureRandom = SecureRandom.getInstance(SECURE_RANDOM_ALGORITHM);
byte[] bytes = new byte[8];
randomSecureRandom.nextBytes(bytes);
ivParameterSpec = new IvParameterSpec(bytes);
}
return ivParameterSpec;
}

}
Loading