package org.expeditee.encryption; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; import java.util.Base64; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import org.expeditee.auth.AuthenticatorBrowser; import org.expeditee.gui.DisplayController; import org.expeditee.gui.Frame; import org.expeditee.gui.FrameIO; import org.expeditee.items.Item; import org.expeditee.items.Text; import org.expeditee.settings.UserSettings; import com.codahale.shamir.Scheme; public class Actions implements CryptographyConstants { public static void TestSurrogate(Item primary) { System.out.println("Test surrogates: "); } public static Text GenerateSecret(String label) { return AuthGenerateSecret(label); } public static Text SplitSecret(Text key) { return AuthSplitSecret(key); } public static Text JoinSecret(Text key) { return AuthJoinSecret(key); } public static void Encrypt(Text labelWithKey) { AuthEncrypt(labelWithKey); } public static void Decrypt(Text labelWithKey) { AuthDecrypt(labelWithKey); } public static Text AuthGenerateSecret(String label) { // Generate AES Key Random rand = new SecureRandom(); byte[] keyBytes = new byte[16]; rand.nextBytes(keyBytes); String key = Base64.getEncoder().encodeToString(keyBytes); Text text = new Text(label); text.setData(key); text.setPosition(DisplayController.getMousePosition()); return text; } public static Text AuthSplitSecret(Text key) { // Retrieve secret String secret = key.getData().get(0); byte[] secretBytes = Base64.getDecoder().decode(secret); // Obtain parameters for shamir String[] arguments = key.getText().split(" "); int requiredShares = Integer.parseInt(arguments[1]); int totalShares = arguments.length - 2; // Create shares Scheme scheme = new Scheme(new SecureRandom(), totalShares, requiredShares); Map split = scheme.split(secretBytes); // Add shares to key List data = key.getData(); for (Integer i: split.keySet()) { data.add("{" + i + "}" + Base64.getEncoder().encodeToString(split.get(i))); } key.setData(data); return key; } public static Text AuthJoinSecret(Text key) { Map contributingParts = new HashMap(); // Retrieve splits List data = key.getData(); for (String d: data) { if (d.startsWith("{")) { String[] split = d.split("}"); Integer k = Integer.parseInt(split[0].replace("{", "")); byte[] v = Base64.getDecoder().decode(split[1]); contributingParts.put(k, v); } } // Obtain parameters for shamir String[] arguments = key.getText().split(" "); int totalShares = Integer.parseInt(arguments[2]); int requiredShares = Integer.parseInt(arguments[1]); // Perform join Scheme scheme = new Scheme(new SecureRandom(), totalShares, requiredShares); byte[] join = scheme.join(contributingParts); data.clear(); data.add(Base64.getEncoder().encodeToString(join)); return key; } public static void AuthEncrypt(Text labelWithKey) { // Obtain encryption key String keyEncoded = labelWithKey.getData().get(0); byte[] keyDecoded = Base64.getDecoder().decode(keyEncoded); SecretKey key = new SecretKeySpec(keyDecoded, SymmetricAlgorithm); // Perform encryption Frame toEncrypt = FrameIO.LoadFrame(labelWithKey.getLink()); Collection textItems = toEncrypt.getTextItems(); for (Text t: textItems) { byte[] encrypted = EncryptSymmetric(t.getText().getBytes(), key); t.setText(Base64.getEncoder().encodeToString(encrypted)); } // Save changes FrameIO.SaveFrame(toEncrypt); } public static void AuthDecrypt(Text labelWithKey) { // Obtain encryption key String keyEncoded = labelWithKey.getData().get(0); byte[] keyDecoded = Base64.getDecoder().decode(keyEncoded); SecretKey key = new SecretKeySpec(keyDecoded, SymmetricAlgorithm); // Perform decryption Frame toDecrypt = FrameIO.LoadFrame(labelWithKey.getLink()); Collection textItems = toDecrypt.getTextItems(); for (Text t: textItems) { byte[] decrypted = DecryptSymmetric(Base64.getDecoder().decode(t.getText().getBytes()), key); t.setText(new String(decrypted)); } // Save changes FrameIO.SaveFrame(toDecrypt); } public static byte[] EncryptSymmetric(final byte[] toEncrypt, final SecretKey key) { // toEncrypt = Base64.getDecoder().decode(toEncrypt); try { final Cipher cipher = Cipher.getInstance(SymmetricAlgorithm + SymmetricAlgorithmParameters); cipher.init(Cipher.ENCRYPT_MODE, key); //could use modulus final int length = (int) ((Math.ceil(toEncrypt.length / 16f)) * 16); final byte[] toEncryptSizeAdjusted = Arrays.copyOf(toEncrypt, length); //System.err.println("(" + toEncryptSizeAdjusted.length + ")" + "Before Encryption Data: " // + Arrays.toString(toEncryptSizeAdjusted)); final byte[] result = cipher.doFinal(toEncryptSizeAdjusted); //System.err.println("(" + result.length + ")" + "Encrypted Data: " + Arrays.toString(result)); return result; } catch (final NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { e.printStackTrace(); return null; } } public static byte[] DecryptSymmetric(final byte[] toDecrypt, final SecretKey key) { try { final Cipher cipher = Cipher.getInstance(SymmetricAlgorithm + SymmetricAlgorithmParameters); cipher.init(Cipher.DECRYPT_MODE, key); final byte[] decryptedBytes = cipher.doFinal(toDecrypt); int indexOfZero = decryptedBytes.length - 1; for (int i = decryptedBytes.length - 1; i >= 0; i--) { if (decryptedBytes[i] != (byte) 0) { indexOfZero = i + 1; break; } } return Arrays.copyOf(decryptedBytes, indexOfZero); } catch (final NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) { e.printStackTrace(); return null; } } public static void AuthAddSecretKey(String name, String data) { Frame secretsFrame = FrameIO.LoadFrame(UserSettings.UserName.get() + AuthenticatorBrowser.SECRETS_FRAME); secretsFrame.addText(500, 500, name, null).addToData(data); } }