diff --git a/.gradle/7.2/executionHistory/executionHistory.bin b/.gradle/7.2/executionHistory/executionHistory.bin index 2ec5586..2a24896 100644 Binary files a/.gradle/7.2/executionHistory/executionHistory.bin and b/.gradle/7.2/executionHistory/executionHistory.bin differ diff --git a/.gradle/7.2/executionHistory/executionHistory.lock b/.gradle/7.2/executionHistory/executionHistory.lock index b31282f..024520e 100644 Binary files a/.gradle/7.2/executionHistory/executionHistory.lock and b/.gradle/7.2/executionHistory/executionHistory.lock differ diff --git a/.gradle/7.2/fileHashes/fileHashes.bin b/.gradle/7.2/fileHashes/fileHashes.bin index 291ac1c..58816f1 100644 Binary files a/.gradle/7.2/fileHashes/fileHashes.bin and b/.gradle/7.2/fileHashes/fileHashes.bin differ diff --git a/.gradle/7.2/fileHashes/fileHashes.lock b/.gradle/7.2/fileHashes/fileHashes.lock index 268ac3f..f858649 100644 Binary files a/.gradle/7.2/fileHashes/fileHashes.lock and b/.gradle/7.2/fileHashes/fileHashes.lock differ diff --git a/.gradle/7.2/fileHashes/resourceHashesCache.bin b/.gradle/7.2/fileHashes/resourceHashesCache.bin index c98df58..89e9bdc 100644 Binary files a/.gradle/7.2/fileHashes/resourceHashesCache.bin and b/.gradle/7.2/fileHashes/resourceHashesCache.bin differ diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 0131094..7fee6bc 100644 Binary files a/.gradle/buildOutputCleanup/buildOutputCleanup.lock and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin index 6066105..52bfb1c 100644 Binary files a/.gradle/buildOutputCleanup/outputFiles.bin and b/.gradle/buildOutputCleanup/outputFiles.bin differ diff --git a/.gradle/checksums/checksums.lock b/.gradle/checksums/checksums.lock index 90d5d2c..9dc656a 100644 Binary files a/.gradle/checksums/checksums.lock and b/.gradle/checksums/checksums.lock differ diff --git a/.gradle/checksums/md5-checksums.bin b/.gradle/checksums/md5-checksums.bin index 0355028..2378b0a 100644 Binary files a/.gradle/checksums/md5-checksums.bin and b/.gradle/checksums/md5-checksums.bin differ diff --git a/.gradle/checksums/sha1-checksums.bin b/.gradle/checksums/sha1-checksums.bin index a7d7b5f..f433d67 100644 Binary files a/.gradle/checksums/sha1-checksums.bin and b/.gradle/checksums/sha1-checksums.bin differ diff --git a/.gradle/checksums/sha256-checksums.bin b/.gradle/checksums/sha256-checksums.bin index e9b11ea..3e2bdd6 100644 Binary files a/.gradle/checksums/sha256-checksums.bin and b/.gradle/checksums/sha256-checksums.bin differ diff --git a/.gradle/checksums/sha512-checksums.bin b/.gradle/checksums/sha512-checksums.bin index 76c5421..b57b66d 100644 Binary files a/.gradle/checksums/sha512-checksums.bin and b/.gradle/checksums/sha512-checksums.bin differ diff --git a/build.gradle b/build.gradle index 0528289..49359cc 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group = 'dev.netcode' -version = '0.0.3' +version = '0.0.4' java { toolchain { @@ -21,7 +21,7 @@ publishing { from components.java groupId = 'dev.netcode' artifactId = 'security' - version = '0.0.3' + version = '0.0.4' pom { name = 'netcodes Java security Utilities' description = 'Security utilities including encryption' diff --git a/src/main/java/dev/netcode/security/encryption/AESEncrypter.java b/src/main/java/dev/netcode/security/encryption/AESEncrypter.java index 9873c38..546cd98 100644 --- a/src/main/java/dev/netcode/security/encryption/AESEncrypter.java +++ b/src/main/java/dev/netcode/security/encryption/AESEncrypter.java @@ -1,6 +1,6 @@ package dev.netcode.security.encryption; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; @@ -26,15 +26,16 @@ public class AESEncrypter { public static SecretKeySpec getKey(String password) { MessageDigest sha = null; SecretKeySpec privateKey = null; + byte[] key = password.getBytes(StandardCharsets.UTF_8); try { - byte[] key = password.getBytes("UTF-8"); sha = MessageDigest.getInstance("SHA-256"); - key = sha.digest(key); - key = Arrays.copyOf(key, 16); - privateKey = new SecretKeySpec(key, "AES"); - } catch(NoSuchAlgorithmException | UnsupportedEncodingException e) { + } catch (NoSuchAlgorithmException e) { + // SHA-256 exists so this should never be thrown e.printStackTrace(); - } + } + key = sha.digest(key); + key = Arrays.copyOf(key, 16); + privateKey = new SecretKeySpec(key, "AES"); return privateKey; } diff --git a/src/main/java/dev/netcode/security/encryption/KeyLoader.java b/src/main/java/dev/netcode/security/encryption/KeyLoader.java index 22b24db..1958dcf 100644 --- a/src/main/java/dev/netcode/security/encryption/KeyLoader.java +++ b/src/main/java/dev/netcode/security/encryption/KeyLoader.java @@ -5,6 +5,7 @@ import java.nio.file.Path; import java.security.PrivateKey; import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; import java.util.Base64; import dev.netcode.util.Result; @@ -19,8 +20,9 @@ public class KeyLoader { * @param file Path of the file containing the Base64 encoded public key * @return the public key * @throws IOException if the file can not be read + * @throws InvalidKeySpecException in case the loaded key is malformed or currupted */ - public static PublicKey loadPublicKeyFromFile(Path file) throws IOException { + public static PublicKey loadPublicKeyFromFile(Path file) throws IOException, InvalidKeySpecException { String publicContent = new String(Files.readAllBytes(file)); publicContent = publicContent.replace("\n", "").replace("\r", ""); publicContent = publicContent.substring(26,publicContent.length()-24); @@ -33,8 +35,9 @@ public static PublicKey loadPublicKeyFromFile(Path file) throws IOException { * @param file Path of the file containing the Base64 encoded private key * @return the private key * @throws IOException if the file can not be read + * @throws InvalidKeySpecException in case the loaded key is malformed or currupted */ - public static PrivateKey loadPrivateKeyFromFile(Path file) throws IOException { + public static PrivateKey loadPrivateKeyFromFile(Path file) throws IOException, InvalidKeySpecException { String privateContent = new String(Files.readAllBytes(file)); privateContent = privateContent.replace("\n", "").replace("\r", ""); privateContent = privateContent.substring(27,privateContent.length()-25); @@ -48,8 +51,9 @@ public static PrivateKey loadPrivateKeyFromFile(Path file) throws IOException { * @param password used to decrypt the file * @return the public key * @throws IOException if the file can not be read + * @throws InvalidKeySpecException in case the loaded key is malformed or currupted */ - public static Result loadPublicKeyFromEncryptedFile(Path file, String password) throws IOException { + public static Result loadPublicKeyFromEncryptedFile(Path file, String password) throws IOException, InvalidKeySpecException { String publicContent = new String(Files.readAllBytes(file)); var result = AESEncrypter.decrypt(publicContent, password); if(!result.wasSuccessful()) { @@ -66,8 +70,9 @@ public static Result loadPublicKeyFromEncryptedFile(Path file, String * @param password used to decrypt the file * @return the private key * @throws IOException if the file can not be read + * @throws InvalidKeySpecException in case the loaded key is malformed or currupted */ - public static Result loadPrivateKeyFromEncryptedFile(Path file, String password) throws IOException { + public static Result loadPrivateKeyFromEncryptedFile(Path file, String password) throws IOException, InvalidKeySpecException { String privateContent = new String(Files.readAllBytes(file)); var result = AESEncrypter.decrypt(privateContent, password); if(!result.wasSuccessful()) { diff --git a/src/main/java/dev/netcode/security/encryption/RSAEncrypter.java b/src/main/java/dev/netcode/security/encryption/RSAEncrypter.java index 5d46f37..194e21e 100644 --- a/src/main/java/dev/netcode/security/encryption/RSAEncrypter.java +++ b/src/main/java/dev/netcode/security/encryption/RSAEncrypter.java @@ -2,6 +2,7 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; @@ -12,6 +13,8 @@ import java.security.PublicKey; import java.security.SecureRandom; import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; @@ -19,6 +22,7 @@ import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; /** * This class simplifies the process of RSA Encrypting data. @@ -49,18 +53,21 @@ public static KeyPair generateKeyPair(int size) { * @param cipher data to be decrypted * @param privateKey to be used to decrypt the data * @return decrypted data as UTF-8 encoded String + * @throws InvalidKeyException in case the key format is not supported + * @throws BadPaddingException in case something failed while padding + * @throws IllegalBlockSizeException in case the blocksize is invalid */ - public static String decrypt(byte[] cipher, PrivateKey privateKey) { + public static String decrypt(byte[] cipher, PrivateKey privateKey) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException { byte[] dec = {}; - Cipher c; + Cipher c = null; try { c = Cipher.getInstance("RSA"); - c.init(Cipher.DECRYPT_MODE, privateKey); - dec = c.doFinal(cipher); - } catch(Exception e) { - System.out.println("Error while decrypting: " + e.getMessage()); + } catch (NoSuchAlgorithmException |NoSuchPaddingException e) { + // RSA exists so this should never be thrown e.printStackTrace(); } + c.init(Cipher.DECRYPT_MODE, privateKey); + dec = c.doFinal(cipher); return new String(dec, StandardCharsets.UTF_8); } @@ -69,21 +76,21 @@ public static String decrypt(byte[] cipher, PrivateKey privateKey) { * @param message to be encrypted * @param publicKey ised to encrypt the data * @return byte array of encrypted data + * @throws InvalidKeyException in case the key format is not supported + * @throws BadPaddingException in case something failed while padding + * @throws IllegalBlockSizeException in case the blocksize is invalid */ - public static byte[] encrypt(String message, PublicKey publicKey) { + public static byte[] encrypt(String message, PublicKey publicKey) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException { Cipher cipher = null; byte[] encrypted = null; try { cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.ENCRYPT_MODE, publicKey); - } catch (Exception e) { - System.out.println("Error while encrypting: " + e.getMessage()); - } - try { - encrypted = cipher.doFinal(message.getBytes("UTF8")); - } catch (IllegalBlockSizeException | BadPaddingException | UnsupportedEncodingException e) { - System.out.println("Error while encrypting: " + e.getMessage()); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + // RSA exists so this should never be thrown + e.printStackTrace(); } + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + encrypted = cipher.doFinal(message.getBytes(StandardCharsets.UTF_8)); return encrypted; } @@ -93,19 +100,22 @@ public static byte[] encrypt(String message, PublicKey publicKey) { * @param privateKey used to sign the data * @param input data to be signed * @return Signature as String + * @throws InvalidKeyException in case the key format is not supported + * @throws SignatureException in case something went wrong while creating the signature */ - public static String sign(PrivateKey privateKey, String input) { + public static String sign(PrivateKey privateKey, String input) throws InvalidKeyException, SignatureException { + Signature privateSignature = null; try { - Signature privateSignature = Signature.getInstance("SHA256withRSA"); - privateSignature.initSign(privateKey); - privateSignature.update(input.getBytes(StandardCharsets.UTF_8)); - - byte[] signature = privateSignature.sign(); - return Base64.getEncoder().encodeToString(signature); - } catch(Exception e) { - System.err.println("Signing failed: "+e.getMessage()); - return null; + privateSignature = Signature.getInstance("SHA256withRSA"); + } catch (NoSuchAlgorithmException e) { + // SHA256withRSA exists so this should never be thrown + e.printStackTrace(); } + privateSignature.initSign(privateKey); + privateSignature.update(input.getBytes(StandardCharsets.UTF_8)); + + byte[] signature = privateSignature.sign(); + return Base64.getEncoder().encodeToString(signature); } /** @@ -134,34 +144,38 @@ public static boolean verifySignature(PublicKey publicKey, String data, String s * Generates a public key from byte array * @param key byte array * @return public key + * @throws InvalidKeySpecException in case the key format is not supported */ - public static PublicKey generatePublicKeyFromString(byte[] key){ - try{ - X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(key); - KeyFactory kf = KeyFactory.getInstance("RSA"); - - return kf.generatePublic(X509publicKey); - } catch(Exception e){ - e.printStackTrace(); - return null; - } + public static PublicKey generatePublicKeyFromString(byte[] key) throws InvalidKeySpecException{ + X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(key); + KeyFactory kf; + try { + kf = KeyFactory.getInstance("RSA"); + } catch (NoSuchAlgorithmException e) { + //should never be thrown + e.printStackTrace(); + return null; + } + return kf.generatePublic(X509publicKey); } /** * Generates a private key from byte array * @param key byte array * @return private key + * @throws InvalidKeySpecException in case the key format is not supported */ - public static PrivateKey generatePrivateKeyFromString(byte[] key){ - try{ - PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key); - KeyFactory kf = KeyFactory.getInstance("RSA"); - - return kf.generatePrivate(pkcs8EncodedKeySpec); - } catch(Exception e){ - e.printStackTrace(); - return null; - } + public static PrivateKey generatePrivateKeyFromString(byte[] key) throws InvalidKeySpecException{ + PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key); + KeyFactory kf; + try { + kf = KeyFactory.getInstance("RSA"); + } catch (NoSuchAlgorithmException e) { + // should never be thrown + e.printStackTrace(); + return null; + } + return kf.generatePrivate(pkcs8EncodedKeySpec); } /** diff --git a/src/main/java/dev/netcode/security/identity/Identity.java b/src/main/java/dev/netcode/security/identity/Identity.java index 8d90a2b..af8b976 100644 --- a/src/main/java/dev/netcode/security/identity/Identity.java +++ b/src/main/java/dev/netcode/security/identity/Identity.java @@ -96,15 +96,19 @@ public boolean save(Path path) { /** * Unlocks a loaded identity which makes it possible to use it * @param password to unlock the identity with - * @return true if the unlocking process was successful + * @return true if the unlocking process was successful, false otherwise */ public boolean unlock(String password) { var result = AESEncrypter.decrypt(this.privateKey, password); if(result.wasSuccessful()) { - this.keyPair = new KeyPair( - RSAEncrypter.generatePublicKeyFromString(Base64.getDecoder().decode(this.publicKey)), - RSAEncrypter.generatePrivateKeyFromString(Base64.getDecoder().decode(result.get())) - ); + try { + this.keyPair = new KeyPair( + RSAEncrypter.generatePublicKeyFromString(Base64.getDecoder().decode(this.publicKey)), + RSAEncrypter.generatePrivateKeyFromString(Base64.getDecoder().decode(result.get())) + ); + } catch(Exception e) { + return false; + } return true; } return false; diff --git a/src/main/java/dev/netcode/security/identity/Signature.java b/src/main/java/dev/netcode/security/identity/Signature.java index 048877d..f491f8f 100644 --- a/src/main/java/dev/netcode/security/identity/Signature.java +++ b/src/main/java/dev/netcode/security/identity/Signature.java @@ -1,7 +1,10 @@ package dev.netcode.security.identity; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; +import java.security.SignatureException; import java.text.SimpleDateFormat; import java.util.Date; @@ -54,8 +57,11 @@ public boolean isValid(PublicKey publicKey, Identity identity) { /** * Signs this Signature which makes it valid. * @param privateKey used to sign the signature + * @throws SignatureException + * @throws NoSuchAlgorithmException + * @throws InvalidKeyException */ - public void sign(PrivateKey privateKey) { + public void sign(PrivateKey privateKey) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException { signature = RSAEncrypter.sign(privateKey, getVerifiableDataString()); }