Skip to content

Commit

Permalink
Merge pull request #15 from MasterFlomaster1/dev
Browse files Browse the repository at this point in the history
First pass on stream ciphers
  • Loading branch information
MasterFlomaster1 authored Jul 16, 2024
2 parents f51968e + ba6993b commit 1ac4184
Show file tree
Hide file tree
Showing 10 changed files with 514 additions and 22 deletions.
35 changes: 35 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Create Release

on:
push:
tags:
- 'v*.*.*'
branches:
- "master"

jobs:
release:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Maven
run: mvn -B package --file pom.xml

- name: Extract version
run: echo "VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
files: |
target/simple-java-crypter-${{ env.VERSION }}.jar
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>dev.masterflomaster1</groupId>
<artifactId>simple-java-crypter</artifactId>
<version>4.0.2</version>
<version>4.0.3</version>

<name>SimpleJavaCrypter</name>
<description>Encryption tool</description>
Expand Down
16 changes: 3 additions & 13 deletions src/main/java/dev/masterflomaster1/sjc/crypto/BlockCipherImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public static void encryptFile(String inputFilePath,
}
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}

Expand Down Expand Up @@ -133,7 +133,7 @@ public static void decryptFile(String inputFilePath,

System.out.println("File decrypted successfully.");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}

Expand Down Expand Up @@ -185,17 +185,7 @@ public static byte[] generateIV(String algorithm) {

public static byte[] generatePasswordBasedKey(char[] password, int keySize) {
var salt = Base64.getDecoder().decode("4WHuOVNv8nIwjrPhLpyPwA==");
return generatePasswordBasedKey(password, keySize, salt);
}

public static byte[] generatePasswordBasedKey(char[] password, int keySize, byte[] salt) {
var f = PbeImpl.asyncHash("PBKDF2", password, salt, 10000, keySize);

try {
return f.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
return SecurityUtils.generatePasswordBasedKey(password, keySize, salt);
}

public enum Mode {
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/dev/masterflomaster1/sjc/crypto/SecurityUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,23 @@
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.Provider;
import java.security.SecureRandom;
import java.security.Security;
import java.util.List;
import java.util.TreeSet;
import java.util.concurrent.ExecutionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class SecurityUtils {

private static final SecureRandom SECURE_RANDOM = new SecureRandom();

private static final TreeSet<String> DIGESTS = new TreeSet<>();
private static final TreeSet<String> HMACS = new TreeSet<>();
private static final TreeSet<String> PBKDFS = new TreeSet<>();
private static final TreeSet<String> BLOCK_CIPHERS = new TreeSet<>();
private static final TreeSet<String> STREAM_CIPHERS = new TreeSet<>();
private static final Pattern OID_PATTERN = Pattern.compile("^(OID\\.)?(\\d+\\.)+\\d+$");

private SecurityUtils() { }
Expand All @@ -35,6 +40,10 @@ public static TreeSet<String> getBlockCiphers() {
return BLOCK_CIPHERS;
}

public static TreeSet<String> getStreamCiphers() {
return STREAM_CIPHERS;
}

public static void init() {
// Setup Unlimited Strength Jurisdiction Policy
Security.setProperty("crypto.policy", "unlimited");
Expand All @@ -61,10 +70,29 @@ public static void init() {
"DSTU7624", "GOST28147", "GOST3412-2015", "IDEA", "NOEKEON",
"RC2", "RC5", "RC6", "RIJNDAEL", "SEED", "SHACAL-2", "SKIPJACK", "SM4", "Serpent", "TEA",
"Threefish-1024", "Threefish-256", "Threefish-512", "Tnepres", "Twofish", "XTEA"));

STREAM_CIPHERS.addAll(List.of("ARC4", "CHACHA", "CHACHA20-POLY1305", "CHACHA7539", "Grain128", "Grainv1",
"HC128", "HC256", "SALSA20", "XSALSA20", "ZUC-128", "ZUC-256", "VMPC", "VMPC-KSA3"));
}

private static boolean isOID(String input) {
Matcher matcher = OID_PATTERN.matcher(input);
return matcher.matches();
}

public static byte[] generatePasswordBasedKey(char[] password, int keySize, byte[] salt) {
var f = PbeImpl.asyncHash("PBKDF2", password, salt, 10000, keySize);

try {
return f.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}

public static byte[] generateIV(int lengthBits) {
byte[] iv = new byte[lengthBits / 8];
SECURE_RANDOM.nextBytes(iv);
return iv;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package dev.masterflomaster1.sjc.crypto;

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;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.List;
import java.util.Optional;

public final class StreamCipherImpl {

private StreamCipherImpl() { }

public static byte[] encrypt(String algorithm, byte[] iv, byte[] inputData, byte[] key) {
try {
SecretKey secretKey = new SecretKeySpec(key, algorithm);
Cipher cipher = Cipher.getInstance(algorithm, "BC");

if (getCorrespondingIvLengthBits(algorithm).isPresent())
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
else
cipher.init(Cipher.ENCRYPT_MODE, secretKey);

return cipher.doFinal(inputData);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | NoSuchProviderException | InvalidKeyException |
IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
}
}

public static byte[] decrypt(String algorithm, byte[] iv, byte[] inputData, byte[] key) {
try {
SecretKey secretKey = new SecretKeySpec(key, algorithm);
Cipher cipher = Cipher.getInstance(algorithm, "BC");

if (getCorrespondingIvLengthBits(algorithm).isPresent())
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
else
cipher.init(Cipher.DECRYPT_MODE, secretKey);

return cipher.doFinal(inputData);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | NoSuchProviderException | InvalidKeyException |
IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
}
}

public static List<Integer> getCorrespondingKeyLengths(String algorithm) {
return switch (algorithm) {
case "ARC4", "Grain128", "HC128", "ZUC-128", "VMPC", "VMPC-KSA3" -> List.of(128);
case "CHACHA", "CHACHA7539", "CHACHA20-POLY1305", "HC256", "ZUC-256", "XSALSA20" -> List.of(256);
case "SALSA20" -> List.of(128, 256);
case "Grainv1" -> List.of(80);
default -> throw new RuntimeException("Unsupported algorithm: " + algorithm);
};
}

public static Optional<List<Integer>> getCorrespondingIvLengthBits(String algorithm) {
return switch (algorithm) {
case "ARC4" -> Optional.empty();
case "CHACHA", "Grainv1", "SALSA20" -> Optional.of(List.of(64));
case "CHACHA7539", "CHACHA20-POLY1305", "Grain128" -> Optional.of(List.of(96));
case "HC128", "ZUC-128" -> Optional.of(List.of(128));
case "HC256" -> Optional.of(List.of(256));
case "XSALSA20" -> Optional.of(List.of(192));
case "ZUC-256" -> Optional.of(List.of(200));
case "VMPC", "VMPC-KSA3" -> Optional.of(List.of(8, 16, 32, 64, 128, 256, 512));
default -> throw new RuntimeException("Unsupported algorithm: " + algorithm);
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import dev.masterflomaster1.sjc.gui.page.components.Pbkdf2Page;
import dev.masterflomaster1.sjc.gui.page.components.PlayfairCipherPage;
import dev.masterflomaster1.sjc.gui.page.components.PwnedPasswordsPage;
import dev.masterflomaster1.sjc.gui.page.components.StreamCipherTextPage;
import dev.masterflomaster1.sjc.gui.page.components.ThemePage;
import dev.masterflomaster1.sjc.gui.page.components.VigenereCipherPage;
import javafx.beans.property.ReadOnlyObjectProperty;
Expand Down Expand Up @@ -82,7 +83,8 @@ private NavTree.Item createTree() {
var symmetricGroup = NavTree.Item.group("Symmetric Encryption", new FontIcon(BootstrapIcons.FILE_EARMARK_LOCK2));
symmetricGroup.getChildren().setAll(
NAV_TREE.get(BlockCipherPage.class),
NAV_TREE.get(BlockCipherFilesPage.class)
NAV_TREE.get(BlockCipherFilesPage.class),
NAV_TREE.get(StreamCipherTextPage.class)
);

var hashGroup = NavTree.Item.group("Unkeyed Hash Functions", new FontIcon(BootstrapIcons.FILE_EARMARK_LOCK2));
Expand Down Expand Up @@ -126,7 +128,8 @@ public static Map<Class<? extends Page>, NavTree.Item> createNavItems() {
map.put(CaesarPage.class, NavTree.Item.page(CaesarPage.NAME, CaesarPage.class));
map.put(VigenereCipherPage.class, NavTree.Item.page(VigenereCipherPage.NAME, VigenereCipherPage.class));
map.put(BlockCipherPage.class, NavTree.Item.page(BlockCipherPage.NAME, BlockCipherPage.class));
map.put(BlockCipherFilesPage.class, NavTree.Item.page(BlockCipherPage.NAME, BlockCipherFilesPage.class));
map.put(BlockCipherFilesPage.class, NavTree.Item.page(BlockCipherFilesPage.NAME, BlockCipherFilesPage.class));
map.put(StreamCipherTextPage.class, NavTree.Item.page(StreamCipherTextPage.NAME, StreamCipherTextPage.class));
map.put(AllHashPage.class, NavTree.Item.page(AllHashPage.NAME, AllHashPage.class));
map.put(HashFilesPage.class, NavTree.Item.page(HashFilesPage.NAME, HashFilesPage.class));
map.put(HmacPage.class, NavTree.Item.page(HmacPage.NAME, HmacPage.class));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

public class BlockCipherFilesPage extends SimplePage {

public static final String NAME = "Block Cipher File Encryption";
public static final String NAME = "Block Cipher Files";

private final TextField keyTextField = new TextField();
private final TextField ivTextField = new TextField();
Expand All @@ -59,7 +59,7 @@ public class BlockCipherFilesPage extends SimplePage {
public BlockCipherFilesPage() {
super();

addSection(NAME, mainSection());
addSection("Block Cipher File Encryption", mainSection());
onInit();

onAlgorithmSelection();
Expand Down Expand Up @@ -224,7 +224,7 @@ private VBox createPasswordModal() {
var generateButton = new Button("Generate");

generateButton.setOnAction(event -> {
var key = BlockCipherImpl.generatePasswordBasedKey(
var key = SecurityUtils.generatePasswordBasedKey(
passwordTextField.getText().toCharArray(),
keyLengthComboBox.getValue(),
HexFormat.of().parseHex(saltTextField.getText())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

public final class BlockCipherPage extends SimplePage {

public static final String NAME = "Block Cipher";
public static final String NAME = "Block Cipher Text";

private final TextArea inputTextArea = new TextArea();
private final TextField keyTextField = new TextField();
Expand All @@ -54,14 +54,15 @@ public final class BlockCipherPage extends SimplePage {
private final ToggleButton b64ModeToggleBtn = new ToggleButton("Base64");

private Timeline emptyIvAnimation;
private Timeline emptyKeyAnimation;

private InputGroup ivGroup;
ModalPane modalPane = new ModalPane();

public BlockCipherPage() {
super();

addSection("Block Cipher", mainSection());
addSection("Block Cipher Text Encryption", mainSection());
onInit();

onAlgorithmSelection();
Expand Down Expand Up @@ -185,6 +186,7 @@ private Node mainSection() {
footerHBox.setAlignment(Pos.CENTER_LEFT);

emptyIvAnimation = Animations.wobble(ivGroup);
emptyKeyAnimation = Animations.wobble(keyGroup);

return new VBox(
20,
Expand Down Expand Up @@ -218,7 +220,7 @@ private VBox createPasswordModal() {
var generateButton = new Button("Generate");

generateButton.setOnAction(event -> {
var key = BlockCipherImpl.generatePasswordBasedKey(
var key = SecurityUtils.generatePasswordBasedKey(
passwordTextField.getText().toCharArray(),
keyLengthComboBox.getValue(),
HexFormat.of().parseHex(saltTextField.getText())
Expand Down Expand Up @@ -267,6 +269,11 @@ private void action(boolean encrypt) {
return;
}

if (keyTextField.getText().isEmpty()) {
emptyKeyAnimation.playFromStart();
return;
}

var text = inputTextArea.getText().getBytes(StandardCharsets.UTF_8);
byte[] key = HexFormat.of().parseHex(keyTextField.getText());
byte[] value;
Expand Down
Loading

0 comments on commit 1ac4184

Please sign in to comment.