diff --git a/.travis.yml b/.travis.yml index bab5140..5c77f1d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,18 @@ language: java jdk: - - oraclejdk8 + - openjdk8 + - oraclejdk9 + - openjdk9 + - oraclejdk11 + - openjdk11 + - oraclejdk13 + - openjdk13 + #- oraclejdk14 + #- openjdk14 + #- oraclejdk15 + #- openjdk15 addons: - sonarqube: + sonarcloud: organization: "kmindi-github" # the key of the org you chose at step #3 cache: directories: diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..1e64ef8 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,118 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.4.2] - 2020-02-16 + +### Changed + +- Changed gradle version to 6.1.1 +- Changed used jdks in travis + +## [0.4.1] - 2018-08-02 + +### Fixed + +- Fixed inclusion of source code links to old files + +## [0.4.0] - 2018-08-02 + +### Changed + +- Changed class names to conform with guidelines +- Added demonstrate-methods for all examples +- Corrected meta format for file encryption example + +### Fixed + +- Added missing UTF-8 encoding in assymetric encryption example +- Fixed file encryption not needing trim anymore +- Fixed Headings according to guidlines +- Fixed import statements not expclicit in file encryption example + +## [0.3.0] - 2018-07-18 + +### Changed + +- Changed PBKDF2 hash function to SHA-512 +- Increased PBKDF2 salt size to 64 bytes (equal to SHA-512 size) +- Increased PBKDF2 iterations to 10000 +- Refactored variable names +- Refactored main methods to call a demonstrate...-method + +### Fixed + +- Exceptions were logged including the stack trace, now only the localized message is logged + +## [0.2.0] - 2018-05-13 + +### Changed + +- Fixed version link in Changelog +- Refactored examples +- Updated class comments + +### Removed + +- Removed easy object oriented examples that used a separate class +- Removed mentions of the need for unlimited policy files (unlimited is default since JDK / Java SE 9) +- Removed commented out code + +## [0.1.1] - 2018-04-28 + +### Changed + +- fixed Changelog + +## [0.1.0] - 2018-04-28 + +### Added + +- added Changelog +- added Asymmetric RSA String Encryption + +## [X.Y.Z] - XXXX-XX-XX (TEMPLATE for new versions) + +### Added + +- added something +- added something else + +### Changed + +- changed something +- changed something else + +### Deprecated + +- deprecated something +- deprecated something else + +### Removed + +- removed something +- removed something else + +### Fixed + +- fixed something +- fixed something else + +### Security + +- made some security relevant changes +- made other security relevant changes + +[Unreleased]: https://github.com/cryptoexamples/java-crypto-examples/compare/v0.4.2...HEAD +[0.4.2]: https://github.com/cryptoexamples/java-crypto-examples/compare/v0.4.1...v0.4.2 +[0.4.1]: https://github.com/cryptoexamples/java-crypto-examples/compare/v0.4.0...v0.4.1 +[0.4.0]: https://github.com/cryptoexamples/java-crypto-examples/compare/v0.3.0...v0.4.0 +[0.3.0]: https://github.com/cryptoexamples/java-crypto-examples/compare/v0.2.0...v0.3.0 +[0.2.0]: https://github.com/cryptoexamples/java-crypto-examples/compare/v0.1.1...v0.2.0 +[0.1.1]: https://github.com/cryptoexamples/java-crypto-examples/compare/v0.1.0...v0.1.1 +[0.1.0]: https://github.com/cryptoexamples/java-crypto-examples/releases/tag/v0.1.0 \ No newline at end of file diff --git a/README.md b/README.md index d2b213f..2414c89 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,21 @@ -# java-crypto-examples for [cryptoexamples.com](http://cryptoexamples.com) +# java-crypto-examples for [CryptoExamples](https://www.cryptoexamples.com) -Example code for cryptographic use cases. Used in [crypto-examples](https://github.com/kmindi/crypto-examples) +Example code for cryptographic use cases. Used in [CryptoExamples](https://github.com/cryptoexamples/CryptoExamples) -![Coverage](https://sonarqube.com/api/badges/measure?key=java-crypto-examples&metric=coverage) -![Technical Debt Ratio](https://sonarqube.com/api/badges/measure?key=java-crypto-examples&metric=sqale_debt_ratio) -![Test Success Density](https://sonarqube.com/api/badges/measure?key=java-crypto-examples&metric=test_success_density) -![Lines Of Code](https://sonarqube.com/api/badges/measure?key=java-crypto-examples&metric=ncloc) +[![Build status](https://travis-ci.org/cryptoexamples/java-crypto-examples.svg?branch=master)](https://travis-ci.org/SonarSource/cryptoexamples/java-crypto-examples) +[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=java-crypto-examples&metric=alert_status)](https://sonarcloud.io/dashboard?id=java-crypto-examples) +[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=java-crypto-examples&metric=sqale_rating)](https://sonarcloud.io/component_measures?id=java-crypto-examples&metric=sqale_rating) +[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=java-crypto-examples&metric=security_rating)](https://sonarcloud.io/component_measures?id=java-crypto-examples&metric=security_rating) +[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=java-crypto-examples&metric=reliability_rating)](https://sonarcloud.io/component_measures?id=java-crypto-examples&metric=reliability_rating) + +[![Code smells](https://sonarcloud.io/api/project_badges/measure?project=java-crypto-examples&metric=code_smells)](https://sonarcloud.io/component_measures?id=java-crypto-examples&metric=code_smells) +[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=java-crypto-examples&metric=bugs)](https://sonarcloud.io/component_measures?id=java-crypto-examples&metric=bugs) +[![Technical debt](https://sonarcloud.io/api/project_badges/measure?project=java-crypto-examples&metric=sqale_index)](https://sonarcloud.io/component_measures?id=java-crypto-examples&metric=sqale_index) +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=java-crypto-examples&metric=coverage)](https://sonarcloud.io/component_measures?id=java-crypto-examples&metric=coverage) +[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=java-crypto-examples&metric=vulnerabilities)](https://sonarcloud.io/component_measures?id=java-crypto-examples&metric=vulnerabilities) +[![Duplicated Lines Density](https://sonarcloud.io/api/project_badges/measure?project=java-crypto-examples&metric=duplicated_lines_density)](https://sonarcloud.io/component_measures?id=java-crypto-examples&metric=duplicated_lines_density) + +![Lines Of Code](https://sonarcloud.io/api/project_badges/measure?project=java-crypto-examples&metric=ncloc) ## License diff --git a/build.gradle b/build.gradle index 8046bbc..83f2747 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id "org.sonarqube" version "2.3" + id "org.sonarqube" version "2.6.2" } group 'com.cryptoexamples.java' @@ -18,16 +18,5 @@ dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' } -tasks.withType(Test) { task -> - jacoco { - append = false - } -} -jacocoTestReport { - reports { - xml.enabled true - csv.enabled false - html.destination "${buildDir}/jacocoHtml" - } -} \ No newline at end of file + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index aa674ec..a362cda 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip diff --git a/java_easy_AES_file_encryption.md b/java_easy_AES_file_encryption.md deleted file mode 100644 index 54bdc4b..0000000 --- a/java_easy_AES_file_encryption.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: Java File Encryption using JDK -keywords: sample -summary: "Java based string encryption" -permalink: java_easy_AES_file_encryption.html -folder: Java JDK -tags: [Java, AES, GCM, PBKDF2, Salt, AEAD] ---- - -## Sample Code for Java based symmetric file encryption - -```java -{% include_relative src/main/java/com/cryptoexamples/java/ExampleEncryptedFile.java %} -``` - -### EncryptedFile encapsulating class using AES-GCM and PBKDF2 -```java -{% include_relative src/main/java/com/cryptoexamples/java/EncryptedFile.java %} -``` - - -{% include links.html %} diff --git a/java_easy_AES_string_encryption.md b/java_easy_AES_string_encryption.md deleted file mode 100644 index a5e8262..0000000 --- a/java_easy_AES_string_encryption.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: Java String Encryption using JDK -keywords: sample -summary: "Java based string encryption" -permalink: java_easy_AES_string_encryption.html -folder: Java JDK -tags: [Java, AES, GCM, PBKDF2, Salt, AEAD] ---- - -## Sample Code for Java based symmetric encryption - -```java -{% include_relative src/main/java/com/cryptoexamples/java/ExampleEncryptedString.java %} -``` - -### EncryptedString Encapsulating class using AES-GCM and PBKDF2 -```java -{% include_relative src/main/java/com/cryptoexamples/java/EncryptedString.java %} -``` - - -{% include links.html %} diff --git a/java_file_encryption_symmetric_password_based.md b/java_file_encryption_symmetric_password_based.md index 583d949..5c7a3a5 100644 --- a/java_file_encryption_symmetric_password_based.md +++ b/java_file_encryption_symmetric_password_based.md @@ -1,21 +1,51 @@ --- -title: Password based symmetric file encryption in Java using JDK +title: Java Password based symmetric file encryption using JDK keywords: sample summary: "Password based symmetric file encryption in Java" permalink: java_file_encryption_symmetric_password_based.html folder: Java JDK +references: [ + # Place a list of references used to create and/or understand this example. + { + url: "https://docs.oracle.com/javase/10/docs/api/javax/crypto/Cipher.html", + description: "Java JDK Ciper" + } +] +authors: [ + { + name: "Kai Mindermann", + url: "https://github.com/kmindi" + } +] +# List all reviewers that reviewed this version of the example. When the example is updated all old reviews +# must be removed from the list below and the code has to be reviewed again. The complete review process +# is documented in the main repository of CryptoExamples +current_reviews: [ + +] +# Indicates when this example was last updated/created. Reviews don't change this. +last_updated: "2020-02-16" tags: [Java, AES, GCM, PBKDF2, Salt, AEAD] --- ## Use cases -- password based encryption of a file -- previously shared common secret (password) +- Password based symmetric encryption of a file + +## Java version + +- openjdk8 +- oraclejdk9 +- openjdk9 +- oraclejdk11 +- openjdk11 +- oraclejdk13 +- openjdk13 -## Sample Code for Java based symmetric file encryption using AES-GCM and PBKDF2 +## Example Code for Java Password based symmetric file encryption using AES-GCM and PBKDF2 ```java -{% include_relative src/main/java/com/cryptoexamples/java/ExampleFileEncryptionInOneMethod.java %} +{% include_relative src/main/java/com/cryptoexamples/java/ExampleFileEncryption.java %} ``` diff --git a/java_landing_page.md b/java_landing_page.md index df75b30..ccdbb84 100644 --- a/java_landing_page.md +++ b/java_landing_page.md @@ -9,11 +9,11 @@ is_landingpage: 1 # Available Crypto Scenarios and Use Cases -| | All in One | Easy Object oriented | -|-------------------------------------------------|----------------------------------------|--------------------------------------| -| Symmetric Encryption | [String Encryption (password based) ✔](java_string_encryption_password_based_symmetric.html)
[String Encryption (key based) ✔](java_string_encryption_key_based_symmetric.html)
[File Encryption ✔](java_file_encryption_symmetric_password_based.html) | [String Encryption with separate class ✔](java_easy_AES_string_encryption.html)
[File Encryption with separate class ✔](java_easy_AES_file_encryption.html) | -| Asymmetric Encryption / Public Key Cryptography | | | -| Key Storage | | | -| Hashing | [String Hash ✔](java_string_hash.html) | N/A | -| Crypto Provider Setup | | | -| Digital Signatures | [String Signing ✔](java_string_sign.html) | | +| | All in One | +|-------------------------------------------------|----------------------------------------| +| Symmetric Encryption | [Symmetric String Encryption (password based) ✔](java_string_encryption_password_based_symmetric.html)
[Symmetric String Encryption (key based) ✔](java_string_encryption_key_based_symmetric.html)
[Symmetric File Encryption ✔](java_file_encryption_symmetric_password_based.html) | +| Asymmetric Encryption / Public Key Cryptography | [Asymmetric String Encryption ✔](java_asymmetric_string_encryption.html) | | +| Key Storage | | +| Hashing | [String Hash ✔](java_string_hash.html) | +| Crypto Provider Setup | | +| Digital Signatures | [String Signing ✔](java_string_sign.html) | diff --git a/java_string_encryption_asymmetric.md b/java_string_encryption_asymmetric.md new file mode 100644 index 0000000..2c0d40c --- /dev/null +++ b/java_string_encryption_asymmetric.md @@ -0,0 +1,51 @@ +--- +title: Java Asymmetric String Encryption using JDK +keywords: sample +summary: "Asymmetric String Encryption in Java" +permalink: java_asymmetric_string_encryption.html +folder: Java JDK +references: [ + # Place a list of references used to create and/or understand this example. + { + url: "https://docs.oracle.com/javase/10/docs/api/javax/crypto/Cipher.html", + description: "Java JDK Ciper" + } +] +authors: [ + { + name: "Kai Mindermann", + url: "https://github.com/kmindi" + } +] +# List all reviewers that reviewed this version of the example. When the example is updated all old reviews +# must be removed from the list below and the code has to be reviewed again. The complete review process +# is documented in the main repository of CryptoExamples +current_reviews: [ + +] +# Indicates when this example was last updated/created. Reviews don't change this. +last_updated: "2020-02-16" +tags: [Java, RSA, Asymmetric, String, Encryption] +--- + +## Use cases + +- Asymmetric encryption + +## Java version + +- openjdk8 +- oraclejdk9 +- openjdk9 +- oraclejdk11 +- openjdk11 +- oraclejdk13 +- openjdk13 + +## Example Code for Java Asymmetric String Encryption using RSA 4096 + +```java +{% include_relative src/main/java/com/cryptoexamples/java/ExampleAsymmetricStringEncryption.java %} +``` + +{% include links.html %} diff --git a/java_string_encryption_key_based_symmetric.md b/java_string_encryption_key_based_symmetric.md index 9a36731..b2fc025 100644 --- a/java_string_encryption_key_based_symmetric.md +++ b/java_string_encryption_key_based_symmetric.md @@ -4,6 +4,27 @@ keywords: sample summary: "String encryption in Java with key generation" permalink: java_string_encryption_key_based_symmetric.html folder: Java JDK +references: [ + # Place a list of references used to create and/or understand this example. + { + url: "https://docs.oracle.com/javase/10/docs/api/javax/crypto/Cipher.html", + description: "Oracle JDK Cipher Documentation" + } +] +authors: [ + { + name: "Kai Mindermann", + url: "https://github.com/kmindi" + } +] +# List all reviewers that reviewed this version of the example. When the example is updated all old reviews +# must be removed from the list below and the code has to be reviewed again. The complete review process +# is documented in the main repository of CryptoExamples +current_reviews: [ + +] +# Indicates when this example was last updated/created. Reviews don't change this. +last_updated: "2020-02-16" tags: [Java, AES, GCM, Salt, AEAD] --- @@ -12,10 +33,20 @@ tags: [Java, AES, GCM, Salt, AEAD] - Random key generation - String encryption -## Sample Code for Java based symmetric encryption using AES-GCM and generation of keys +## Java version + +- openjdk8 +- oraclejdk9 +- openjdk9 +- oraclejdk11 +- openjdk11 +- oraclejdk13 +- openjdk13 + +## Example Code for Java String Encryption with key generation using AES-GCM ```java -{% include_relative src/main/java/com/cryptoexamples/java/ExampleStringEncryptionKeyBasedInOneMethod.java %} +{% include_relative src/main/java/com/cryptoexamples/java/ExampleStringEncryptionKeyBased.java %} ``` diff --git a/java_string_encryption_password_based_symmetric.md b/java_string_encryption_password_based_symmetric.md index b5de4ae..0e5ba9c 100644 --- a/java_string_encryption_password_based_symmetric.md +++ b/java_string_encryption_password_based_symmetric.md @@ -4,6 +4,27 @@ keywords: sample summary: "Password based string encryption in Java" permalink: java_string_encryption_password_based_symmetric.html folder: Java JDK +references: [ + # Place a list of references used to create and/or understand this example. + { + url: "https://docs.oracle.com/javase/10/docs/api/javax/crypto/Cipher.html", + description: "Oracle JDK Cipher Documentation" + } +] +authors: [ + { + name: "Kai Mindermann", + url: "https://github.com/kmindi" + } +] +# List all reviewers that reviewed this version of the example. When the example is updated all old reviews +# must be removed from the list below and the code has to be reviewed again. The complete review process +# is documented in the main repository of CryptoExamples +current_reviews: [ + +] +# Indicates when this example was last updated/created. Reviews don't change this. +last_updated: "2020-02-16" tags: [Java, AES, GCM, PBKDF2, Salt, AEAD] --- @@ -11,12 +32,21 @@ tags: [Java, AES, GCM, PBKDF2, Salt, AEAD] - Password based encryption - Previously shared common secret (password) -- -## Sample Code for Java based symmetric encryption using AES-GCM and PBKDF2 +## Java version + +- openjdk8 +- oraclejdk9 +- openjdk9 +- oraclejdk11 +- openjdk11 +- oraclejdk13 +- openjdk13 + +## Example Code for Java Password Based String Encryption using AES-GCM and PBKDF2 ```java -{% include_relative src/main/java/com/cryptoexamples/java/ExampleStringEncryptionPasswordBasedInOneMethod.java %} +{% include_relative src/main/java/com/cryptoexamples/java/ExampleStringEncryptionPasswordBased.java %} ``` diff --git a/java_string_hash.md b/java_string_hash.md index dbc9a80..08dbd49 100644 --- a/java_string_hash.md +++ b/java_string_hash.md @@ -4,17 +4,48 @@ keywords: sample summary: "Java based string hashing" permalink: java_string_hash.html folder: Java JDK +references: [ + # Place a list of references used to create and/or understand this example. + { + url: "https://docs.oracle.com/javase/10/docs/api/java/security/MessageDigest.html", + description: "Oracle JDK MessageDigest Documentation" + } +] +authors: [ + { + name: "Kai Mindermann", + url: "https://github.com/kmindi" + } +] +# List all reviewers that reviewed this version of the example. When the example is updated all old reviews +# must be removed from the list below and the code has to be reviewed again. The complete review process +# is documented in the main repository of CryptoExamples +current_reviews: [ + +] +# Indicates when this example was last updated/created. Reviews don't change this. +last_updated: "2020-02-16" tags: [Java, hash, SHA, SHA-512] --- ## Use cases -- verifying if a string has been changed +- Verifying if a string has been changed + +## Java version + +- openjdk8 +- oraclejdk9 +- openjdk9 +- oraclejdk11 +- openjdk11 +- oraclejdk13 +- openjdk13 -## Sample Code for Java based hasing of a String using SHA-512, BASE64 and UTF-8 encoding +## Example Code for Java String Hashing using SHA-512, BASE64 and UTF-8 encoding ```java -{% include_relative src/main/java/com/cryptoexamples/java/ExampleHashInOneMethod.java %} +{% include_relative src/main/java/com/cryptoexamples/java/ExampleHash.java %} ``` diff --git a/java_string_sign.md b/java_string_sign.md index 446ed84..d4b2d74 100644 --- a/java_string_sign.md +++ b/java_string_sign.md @@ -4,6 +4,27 @@ keywords: sample summary: "Java based string signing" permalink: java_string_sign.html folder: Java JDK +references: [ + # Place a list of references used to create and/or understand this example. + { + url: "https://docs.oracle.com/javase/10/docs/api/java/security/Signature.html", + description: "Oracle JDK Signature Documentation" + } +] +authors: [ + { + name: "Kai Mindermann", + url: "https://github.com/kmindi" + } +] +# List all reviewers that reviewed this version of the example. When the example is updated all old reviews +# must be removed from the list below and the code has to be reviewed again. The complete review process +# is documented in the main repository of CryptoExamples +current_reviews: [ + +] +# Indicates when this example was last updated/created. Reviews don't change this. +last_updated: "2020-02-16" tags: [Java, hash, SHA, SHA-512] --- @@ -11,10 +32,20 @@ tags: [Java, hash, SHA, SHA-512] - verifying if a string has been changed -## Sample Code for Java based signing of a String using SHA-512, RSA 4096, BASE64 and UTF-8 encoding +## Java version + +- openjdk8 +- oraclejdk9 +- openjdk9 +- oraclejdk11 +- openjdk11 +- oraclejdk13 +- openjdk13 + +## Example Code for Java String Signing using SHA-512, RSA 4096, BASE64 and UTF-8 encoding ```java -{% include_relative src/main/java/com/cryptoexamples/java/ExampleSignatureInOneMethod.java %} +{% include_relative src/main/java/com/cryptoexamples/java/ExampleSignature.java %} ``` diff --git a/src/main/java/com/cryptoexamples/java/EncryptedFile.java b/src/main/java/com/cryptoexamples/java/EncryptedFile.java deleted file mode 100644 index e2b894d..0000000 --- a/src/main/java/com/cryptoexamples/java/EncryptedFile.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.cryptoexamples.java; - -import javax.crypto.*; -import javax.crypto.spec.GCMParameterSpec; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.SecretKeySpec; -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.security.GeneralSecurityException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.spec.KeySpec; -import java.util.Base64; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Encapsulating class for saving a String encrypted in a file and to decrypt/retrieve it. - * - * Including - * - Random password generation using strong secure random number generator - * - Random salt generation - * - Key derivation using PBKDF2 HMAC SHA-256, - * - AES-256 authenticated encryption using GCM - * - UTF-8 encoding - * // TODO store all encryption parameters (as authenticated data) prepended to the file content - * // TODO use Cryptographic Message Snytax (https://tools.ietf.org/html/rfc5652) - */ -public class EncryptedFile implements Serializable { - private static final Logger LOGGER = Logger.getLogger(EncryptedFile.class.getName()); - - /* 128, 120, 112, 104, or 96 @see NIST Special Publication 800-38D*/ - private static final int DEFAULT_GCM_AUTHENTICATION_TAG_SIZE_BITS = 128; - - private static final int DEFAULT_GCM_IV_NONCE_SIZE_BYTES = 12; - private static final int DEFAULT_PBKDF2_ITERATIONS = 65536; - private static final int DEFAULT_PBKDF2_SALT_SIZE_BYTES = 32; - - /* @see https://www.keylength.com/ */ - private static final int DEFAULT_AES_KEY_LENGTH_BITS = 256; - private static final String DEFAULT_CIPHER = "AES"; - private static final String DEFAULT_CIPHERSCHEME = "AES/GCM/NoPadding"; - private static final String DEFAULT_PBKDF2_SCHEME = "PBKDF2WithHmacSHA256"; - - private int gcmAuthenticationTagSizeBits = DEFAULT_GCM_AUTHENTICATION_TAG_SIZE_BITS; - private int gcmIvNonceSizeBytes = DEFAULT_GCM_IV_NONCE_SIZE_BYTES; - private int pbkdf2Iterations = DEFAULT_PBKDF2_ITERATIONS; - private int pbkdf2SaltSizeBytes = DEFAULT_PBKDF2_SALT_SIZE_BYTES; - private int aesKeyLengthBits = DEFAULT_AES_KEY_LENGTH_BITS; - private String cipher = DEFAULT_CIPHER; - private String cipherscheme = DEFAULT_CIPHERSCHEME; - private String pbkdf2Scheme = DEFAULT_PBKDF2_SCHEME; - - /** - * Creates a new empty EncryptedFile object - */ - public EncryptedFile() { - // uses default parameters, see initialization at the beginning. - } - - /** - * Generates a randomly filled byte array - * - * @param sizeInBytes length of the array in bytes - * @return byte array containing random values - * @throws NoSuchAlgorithmException - */ - private static byte[] generateRandomArry(int sizeInBytes) throws NoSuchAlgorithmException { - /* generate random salt */ - final byte[] salt = new byte[sizeInBytes]; - SecureRandom random = SecureRandom.getInstanceStrong(); - random.nextBytes(salt); - return salt; - } - - /** - * Generates a random password. - * - * @param sizeInBytes length of the password in byte - * @return Base64 encoded string with a random password - * @throws NoSuchAlgorithmException - */ - public static String generatePassword(int sizeInBytes) throws NoSuchAlgorithmException { - return Base64.getEncoder().encodeToString(generateRandomArry(sizeInBytes)); - } - - /** - * Encrypts the provided plainText using the provided password and stores it in a file - * - * @param plainText plaintext that should be encrypted - * @param password password which is used to generate the key - * @param path path to a writeable file (may already exist) - * @throws GeneralSecurityException - */ - public void encrypt(String plainText, String password, String path) throws GeneralSecurityException { - /* Derive the key*/ - SecretKeyFactory factory = SecretKeyFactory.getInstance(pbkdf2Scheme); - byte[] newSalt = generateRandomArry(pbkdf2SaltSizeBytes); - KeySpec keyspec = new PBEKeySpec(password.toCharArray(), newSalt, pbkdf2Iterations, aesKeyLengthBits); - SecretKey tmp = factory.generateSecret(keyspec); - SecretKey key = new SecretKeySpec(tmp.getEncoded(), cipher); - - Cipher myCipher = Cipher.getInstance(cipherscheme); - byte[] newNonce = generateRandomArry(gcmIvNonceSizeBytes); - GCMParameterSpec spec = new GCMParameterSpec(gcmAuthenticationTagSizeBits, newNonce); - myCipher.init(Cipher.ENCRYPT_MODE, key, spec); - - // SET UP OUTPUT STREAM and write content of String - try ( - FileOutputStream fileOutputStream = new FileOutputStream(path); - CipherOutputStream encryptedOutputStream = new CipherOutputStream(fileOutputStream, myCipher); - InputStream stringInputStream = new ByteArrayInputStream(plainText.getBytes(StandardCharsets.UTF_8)); - ) { - // write IV/nonce - fileOutputStream.write(newNonce); - - // write salt - fileOutputStream.write(newSalt); - - byte[] buffer = new byte[8192]; - while (stringInputStream.read(buffer) > 0) { - encryptedOutputStream.write(buffer); - } - } catch (IOException e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); - throw new SecurityException(e.getMessage(), e); - } - } - - /** - * Decrypts the cipherText using the provided password. - * - * @param password password which is used to generate the key - * @param path path to a previously encrypted file to be decrypted - * @return plaintext - * @throws GeneralSecurityException - */ - public String decrypt(String password, String path ) throws GeneralSecurityException { - - // Read configuration from file - - byte[] myNonce = new byte[gcmIvNonceSizeBytes]; - byte[] mySalt = new byte[pbkdf2SaltSizeBytes]; - - try ( - FileInputStream fileInputStream = new FileInputStream(path); - ) { - int countReadBytesNonce = fileInputStream.read(myNonce); - int countReadBytesSalt = fileInputStream.read(mySalt); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); - throw new SecurityException(e.getMessage(), e); - } - - /* Derive the key*/ - SecretKeyFactory factory = SecretKeyFactory.getInstance(pbkdf2Scheme); - // Needs unlimited strength policy files http://www.oracle.com/technetwork/java/javase/downloads - KeySpec keyspec = new PBEKeySpec(password.toCharArray(), mySalt, pbkdf2Iterations, aesKeyLengthBits); - SecretKey tmp = factory.generateSecret(keyspec); - SecretKey key = new SecretKeySpec(tmp.getEncoded(), cipher); - - Cipher myCipher = Cipher.getInstance(cipherscheme); - GCMParameterSpec spec = new GCMParameterSpec(gcmAuthenticationTagSizeBits, myNonce); - - myCipher.init(Cipher.DECRYPT_MODE, key, spec); - - // READ ENCRYPTED FILE - StringBuilder stringBuilder = new StringBuilder(); - - //cipher.updateAAD(aad); - try ( - FileInputStream fileInputStream = new FileInputStream(path); - CipherInputStream cipherInputStream = new CipherInputStream(fileInputStream, myCipher); - ) { - // offset the stream by the bytes already read previosly - - // TODO check if file has this bytes at least. - byte[] skipped = new byte[gcmIvNonceSizeBytes+pbkdf2SaltSizeBytes]; - int read = fileInputStream.read(skipped); - - byte[] buffer = new byte[8192]; - while (cipherInputStream.read(buffer) > 0) { - stringBuilder.append(new String(buffer, StandardCharsets.UTF_8)); - } - } catch (IOException e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); - throw new SecurityException(e.getMessage(), e); - } - - // TODO trim() should not be needed! - return stringBuilder.toString().trim(); - } -} - diff --git a/src/main/java/com/cryptoexamples/java/EncryptedString.java b/src/main/java/com/cryptoexamples/java/EncryptedString.java deleted file mode 100644 index fd1b7b9..0000000 --- a/src/main/java/com/cryptoexamples/java/EncryptedString.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.cryptoexamples.java; - -import javax.crypto.Cipher; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.GCMParameterSpec; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.SecretKeySpec; -import java.io.Serializable; -import java.security.GeneralSecurityException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.spec.KeySpec; -import java.util.Base64; - -/** - * Encapsulating class for encrypting and decrypting strings - * Including - * - Random password generation using strong secure random number generator - * - Random salt generation - * - Key derivation using PBKDF2 HMAC SHA-256, - * - AES-256 authenticated encryption using GCM - * - BASE64-encoding as representation for the byte-arrays - */ -public class EncryptedString implements Serializable { - - /* 128, 120, 112, 104, or 96 @see NIST Special Publication 800-38D*/ - private static final int DEFAULT_GCM_AUTHENTICATION_TAG_SIZE_BITS = 128; - - private static final int DEFAULT_GCM_IV_NONCE_SIZE_BYTES = 12; - private static final int DEFAULT_PBKDF2_ITERATIONS = 65536; - private static final int DEFAULT_PBKDF2_SALT_SIZE_BYTES = 32; - - /* @see https://www.keylength.com/ */ - private static final int DEFAULT_AES_KEY_LENGTH_BITS = 256; - private static final String DEFAULT_CIPHER = "AES"; - private static final String DEFAULT_CIPHERSCHEME = "AES/GCM/NoPadding"; - private static final String DEFAULT_PBKDF2_SCHEME = "PBKDF2WithHmacSHA256"; - - private int gcmAuthenticationTagSizeBits = DEFAULT_GCM_AUTHENTICATION_TAG_SIZE_BITS; - private int gcmIvNonceSizeBytes = DEFAULT_GCM_IV_NONCE_SIZE_BYTES; - private int pbkdf2Iterations = DEFAULT_PBKDF2_ITERATIONS; - private int pbkdf2SaltSizeBytes = DEFAULT_PBKDF2_SALT_SIZE_BYTES; - private int aesKeyLengthBits = DEFAULT_AES_KEY_LENGTH_BITS; - private String cipher = DEFAULT_CIPHER; - private String cipherscheme = DEFAULT_CIPHERSCHEME; - private String pbkdf2Scheme = DEFAULT_PBKDF2_SCHEME; - - private byte[] nonce; - private byte[] salt; - private String cipherText; - - /** - * Creates a new com.cryptoexamples.java.EncryptedString object based on cipherText, nonce and salt. - * - * @param cipherText encrypted plaintext (generated from encrypt) - * @param nonce byte array, number used once (random) see gcmIvNonceSizeBytes - * @param salt random byte array to prevent rainbow table attacks on password lists - */ - public EncryptedString(String cipherText, byte[] nonce, byte[] salt) { - this.cipherText = cipherText; - this.nonce = nonce; - this.salt = salt; - } - - /** - * Initializes this com.cryptoexamples.java.EncryptedString object with the provided parameters - * - * @param cipher - * @param cipherscheme - * @param gcmAuthenticationTagSizeBits - * @param gcmIvNonceSizeBytes - * @param pbkdf2Iterations - * @param pbkdf2SaltSizeBytes - * @param aesKeyLengthBits - * @param pbkdf2Scheme - */ - private EncryptedString(String cipherText, byte[] nonce, byte[] salt, String cipher, String cipherscheme, int gcmAuthenticationTagSizeBits, int gcmIvNonceSizeBytes, int pbkdf2Iterations, int pbkdf2SaltSizeBytes, int aesKeyLengthBits, String pbkdf2Scheme) { - this.cipherText = cipherText; - this.nonce = nonce; - this.salt = salt; - - this.cipher = cipher; - this.cipherscheme = cipherscheme; - this.gcmAuthenticationTagSizeBits = gcmAuthenticationTagSizeBits; - this.gcmIvNonceSizeBytes = gcmIvNonceSizeBytes; - this.pbkdf2Iterations = pbkdf2Iterations; - this.pbkdf2SaltSizeBytes = pbkdf2SaltSizeBytes; - this.aesKeyLengthBits = aesKeyLengthBits; - this.pbkdf2Scheme = pbkdf2Scheme; - } - - /** - * Creates a new empty com.cryptoexamples.java.EncryptedString object - */ - public EncryptedString() { - // uses default parameters, see initialization at the beginning. - } - - /** - * Generates a randomly filled byte array - * - * @param sizeInBytes length of the array in bytes - * @return byte array containing random values - * @throws NoSuchAlgorithmException - */ - private static byte[] generateRandomArry(int sizeInBytes) throws NoSuchAlgorithmException { - /* generate random salt */ - final byte[] salt = new byte[sizeInBytes]; - SecureRandom random = SecureRandom.getInstanceStrong(); - random.nextBytes(salt); - return salt; - } - - /** - * Generates a random password. - * - * @param sizeInBytes length of the password in byte - * @return Base64 encoded string with a random password - * @throws NoSuchAlgorithmException - */ - public static String generatePassword(int sizeInBytes) throws NoSuchAlgorithmException { - return Base64.getEncoder().encodeToString(generateRandomArry(sizeInBytes)); - } - - private byte[] getNonce() { - return this.nonce; - } - - private byte[] getSalt() { - return this.salt; - } - - private String getCipherText() { - return this.cipherText; - } - - /** - * Encrypts the provided plainText using the provided password. - * - * @param plainText plaintext that should be encrypted - * @param password password which is used to generate the key - * @return new com.cryptoexamples.java.EncryptedString object - * @throws GeneralSecurityException - */ - public EncryptedString encrypt(String plainText, String password) throws GeneralSecurityException { - /* Derive the key*/ - SecretKeyFactory factory = SecretKeyFactory.getInstance(pbkdf2Scheme); - byte[] newSalt = generateRandomArry(pbkdf2SaltSizeBytes); - KeySpec keyspec = new PBEKeySpec(password.toCharArray(), newSalt, pbkdf2Iterations, aesKeyLengthBits); - SecretKey tmp = factory.generateSecret(keyspec); - SecretKey key = new SecretKeySpec(tmp.getEncoded(), cipher); - - Cipher myCipher = Cipher.getInstance(cipherscheme); - byte[] newNonce = generateRandomArry(gcmIvNonceSizeBytes); - GCMParameterSpec spec = new GCMParameterSpec(gcmAuthenticationTagSizeBits, newNonce); - myCipher.init(Cipher.ENCRYPT_MODE, key, spec); - - byte[] byteCipher = myCipher.doFinal(plainText.getBytes()); - - return new EncryptedString(new String(Base64.getEncoder().encode(byteCipher)), newNonce, newSalt, this.cipher, cipherscheme, gcmAuthenticationTagSizeBits, gcmIvNonceSizeBytes, pbkdf2Iterations, pbkdf2SaltSizeBytes, aesKeyLengthBits, pbkdf2Scheme); - } - - /** - * Decrypts the cipherText using the provided password. - * - * @param password password which is used to generate the key - * @return plaintext - * @throws GeneralSecurityException - */ - public String decrypt(String password) throws GeneralSecurityException { - /* Derive the key*/ - SecretKeyFactory factory = SecretKeyFactory.getInstance(pbkdf2Scheme); - // Needs unlimited strength policy files http://www.oracle.com/technetwork/java/javase/downloads - KeySpec keyspec = new PBEKeySpec(password.toCharArray(), getSalt(), pbkdf2Iterations, aesKeyLengthBits); - SecretKey tmp = factory.generateSecret(keyspec); - SecretKey key = new SecretKeySpec(tmp.getEncoded(), cipher); - - Cipher myCipher = Cipher.getInstance(cipherscheme); - GCMParameterSpec spec = new GCMParameterSpec(gcmAuthenticationTagSizeBits, getNonce()); - - myCipher.init(Cipher.DECRYPT_MODE, key, spec); - - byte[] decryptedCipher = myCipher.doFinal(Base64.getDecoder().decode(getCipherText())); - return new String(decryptedCipher); - } -} - diff --git a/src/main/java/com/cryptoexamples/java/ExampleAsymmetricStringEncryption.java b/src/main/java/com/cryptoexamples/java/ExampleAsymmetricStringEncryption.java new file mode 100644 index 0000000..b5c84c3 --- /dev/null +++ b/src/main/java/com/cryptoexamples/java/ExampleAsymmetricStringEncryption.java @@ -0,0 +1,55 @@ +package com.cryptoexamples.java; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Example for asymmetric encryption and decryption of a string in one method. + * - Generation of public and private RSA 4096 bit keypair + * - BASE64 encoding as representation for the byte-arrays + * - UTF-8 encoding of Strings + * - Exception handling + */ +public class ExampleAsymmetricStringEncryption { + private static final Logger LOGGER = Logger.getLogger(ExampleAsymmetricStringEncryption.class.getName()); + + public static void main(String[] args) { + String plainText = "Text that is going to be sent over an insecure channel and must be encrypted at all costs!"; + try { + // GENERATE NEW KEYPAIR + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + /* @see https://www.keylength.com/ */ + keyPairGenerator.initialize(4096); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + // ENCRYPTION + Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); + cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic()); + + byte[] cipherTextBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); + + // CONVERSION of raw bytes to BASE64 representation + String cipherText = Base64.getEncoder().encodeToString(cipherTextBytes); + + // DECRYPTION + cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); + byte[] decryptedCipherTextBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText)); + String decryptedCipherText = new String(decryptedCipherTextBytes,StandardCharsets.UTF_8); + + LOGGER.log(Level.INFO, () -> String.format("Decrypted and original plain text are the same: %b", decryptedCipherText.compareTo(plainText) == 0)); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | InvalidParameterException e) { + LOGGER.log(Level.SEVERE, e.getLocalizedMessage()); + } + } +} diff --git a/src/main/java/com/cryptoexamples/java/ExampleEncryptedFile.java b/src/main/java/com/cryptoexamples/java/ExampleEncryptedFile.java deleted file mode 100644 index b45eeb6..0000000 --- a/src/main/java/com/cryptoexamples/java/ExampleEncryptedFile.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.cryptoexamples.java; - -import java.security.GeneralSecurityException; -import java.util.logging.Level; -import java.util.logging.Logger; - -// TODO check if KeyStore should be used - -/** - * Object oriented example for encryption and decryption of a string; - * Including - * - Random password generation using strong secure random number generator - * - Random salt generation - * - Key derivation using PBKDF2 HMAC SHA-256, - * - AES-256 authenticated encryption using GCM - * - BASE64-encoding as representation for the byte-arrays - * - Exception handling - */ -public class ExampleEncryptedFile { - private static final Logger LOGGER = Logger.getLogger(ExampleEncryptedFile.class.getName()); - - public static void main(String[] args) { - String plainText = "Text that is going to be sent over an insecure channel and must be encrypted at all costs!"; - - try { - // GENERATE a password (if a password exists, use that). - String password = EncryptedFile.generatePassword(32); - String path = "encryptedFile.enc"; - - - // ENCRYPTION - new EncryptedFile().encrypt(plainText, password, path); - - // DECRYPTION - String decryptedCipherText = new EncryptedFile().decrypt(password, path); - - LOGGER.log(Level.INFO, () -> String.format("Decrypted and original plain text are the same: %b", decryptedCipherText.compareTo(plainText) == 0)); - } catch (GeneralSecurityException e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); - } - } - -} diff --git a/src/main/java/com/cryptoexamples/java/ExampleEncryptedString.java b/src/main/java/com/cryptoexamples/java/ExampleEncryptedString.java deleted file mode 100644 index 2d30af1..0000000 --- a/src/main/java/com/cryptoexamples/java/ExampleEncryptedString.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.cryptoexamples.java; - -import java.security.GeneralSecurityException; -import java.util.logging.Level; -import java.util.logging.Logger; - -// TODO check if KeyStore should be used - -/** - * Object oriented example for encryption and decryption of a string; - * Including - * - Random password generation using strong secure random number generator - * - random salt generation - * - Key derivation using PBKDF2 HMAC SHA-256, - * - AES-256 authenticated encryption using GCM - * - BASE64-encoding as representation for the byte-arrays - * - Exception handling - */ -public class ExampleEncryptedString { - private static final Logger LOGGER = Logger.getLogger(ExampleEncryptedString.class.getName()); - - public static void main(String[] args) { - String plainText = "Text that is going to be sent over an insecure channel and must be encrypted at all costs!"; - - try { - // GENERATE a password (if a password exists, use that). - String password = EncryptedString.generatePassword(32); - - // ENCRYPTION - EncryptedString encryptedString = new EncryptedString().encrypt(plainText, password); - - // DECRYPTION - String decryptedCipherText = encryptedString.decrypt(password); - - LOGGER.log(Level.INFO, () -> String.format("Decrypted and original plain text are the same: %b", decryptedCipherText.compareTo(plainText) == 0)); - } catch (GeneralSecurityException e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); - } - } - -} diff --git a/src/main/java/com/cryptoexamples/java/ExampleFileEncryption.java b/src/main/java/com/cryptoexamples/java/ExampleFileEncryption.java new file mode 100644 index 0000000..d1404db --- /dev/null +++ b/src/main/java/com/cryptoexamples/java/ExampleFileEncryption.java @@ -0,0 +1,127 @@ +package com.cryptoexamples.java; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.KeyGenerator; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.util.Base64; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Example for encryption and decryption of a file in one method. + * - Random password generation using strong secure random number generator + * - Random salt generation + * - Key derivation using PBKDF2 HMAC SHA-512, + * - AES-256 authenticated encryption using GCM + * - BASE64-encoding as representation for the byte-arrays + * - Exception handling + */ +public class ExampleFileEncryption { + private static final Logger LOGGER = Logger.getLogger(ExampleFileEncryption.class.getName()); + + /** + * Demonstrational method that encrypts a file using a password (that is used to derive the required key). + * @param fileName + * @param plainText + * @param password + * @return true if encryption and decryption were successful, false otherwise + */ + public static boolean demonstrateFileEncryption(String fileName, String plainText, String password) { + try { + // GENERATE password (not needed if you have a password already) + if(password == null || password.isEmpty()) { + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + password = Base64.getEncoder().encodeToString(keyGen.generateKey().getEncoded()); + } + + // GENERATE random salt + final byte[] salt = new byte[64]; + SecureRandom random = SecureRandom.getInstanceStrong(); + random.nextBytes(salt); + + // DERIVE key (from password and salt) + SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512"); + KeySpec passwordBasedEncryptionKeySpec = new PBEKeySpec(password.toCharArray(), salt, 10000, 256); + SecretKey secretKeyFromPBKDF2 = secretKeyFactory.generateSecret(passwordBasedEncryptionKeySpec); + SecretKey key = new SecretKeySpec(secretKeyFromPBKDF2.getEncoded(), "AES"); + + // GENERATE random nonce (number used once) + final byte[] nonce = new byte[32]; + random.nextBytes(nonce); + + // SET UP CIPHER for encryption + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + GCMParameterSpec spec = new GCMParameterSpec(16 * 8, nonce); + cipher.init(Cipher.ENCRYPT_MODE, key, spec); + + // TODO store encryption parameters as authenticated data prepended to the file content + + // SET UP OUTPUT STREAM and write content of String + try ( + FileOutputStream fileOutputStream = new FileOutputStream(fileName); + CipherOutputStream encryptedOutputStream = new CipherOutputStream(fileOutputStream, cipher); + InputStream stringInputStream = new ByteArrayInputStream(plainText.getBytes(StandardCharsets.UTF_8)) + ) { + byte[] buffer = new byte[8192]; + int nread; + while ((nread = stringInputStream.read(buffer)) > 0) { + encryptedOutputStream.write(buffer, 0, nread); + } + encryptedOutputStream.flush(); + } + + // READ ENCRYPTED FILE + StringBuilder stringBuilder = new StringBuilder(); + cipher.init(Cipher.DECRYPT_MODE, key, spec); + String decryptedCipherText; + try ( + FileInputStream fileInputStream = new FileInputStream(fileName); + CipherInputStream cipherInputStream = new CipherInputStream(fileInputStream, cipher); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ) { + byte[] buffer = new byte[8192]; + int nread; + while ((nread = cipherInputStream.read(buffer)) > 0) { + byteArrayOutputStream.write(buffer, 0, nread); + } + byteArrayOutputStream.flush(); + decryptedCipherText = new String(byteArrayOutputStream.toByteArray(), StandardCharsets.UTF_8); + } + + LOGGER.log(Level.INFO, decryptedCipherText); + LOGGER.log(Level.INFO, + () -> String.format("Decrypted file content and original plain text are the same: %b", + decryptedCipherText.compareTo(plainText) == 0) + ); + return decryptedCipherText.compareTo(plainText) == 0; + } catch (NoSuchAlgorithmException | + NoSuchPaddingException | + InvalidKeyException | + InvalidParameterException | + InvalidAlgorithmParameterException | + InvalidKeySpecException | + IOException e) { + LOGGER.log(Level.SEVERE, e.getLocalizedMessage()); + return false; + } + } + + + public static void main(String[] args) { + demonstrateFileEncryption("encryptedFile.enc","Multiline text:\nMultiline text:\n",null ); + } + +} diff --git a/src/main/java/com/cryptoexamples/java/ExampleFileEncryptionInOneMethod.java b/src/main/java/com/cryptoexamples/java/ExampleFileEncryptionInOneMethod.java deleted file mode 100644 index ef89604..0000000 --- a/src/main/java/com/cryptoexamples/java/ExampleFileEncryptionInOneMethod.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.cryptoexamples.java; - -import javax.crypto.*; -import javax.crypto.spec.GCMParameterSpec; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.SecretKeySpec; -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.security.*; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; -import java.util.Base64; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * All in one example for encryption and decryption of a file in one method; - * Including - * - Random password generation using strong secure random number generator - * - Random salt generation - * - Key derivation using PBKDF2 HMAC SHA-256, - * - AES-256 authenticated encryption using GCM - * - BASE64-encoding as representation for the byte-arrays - * - Exception handling - */ -public class ExampleFileEncryptionInOneMethod { - private static final Logger LOGGER = Logger.getLogger(ExampleFileEncryptionInOneMethod.class.getName()); - - public static void main(String[] args) { - String plainText = "Multiline text:"; - try { - // GENERATE password - KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - // Needs unlimited strength policy files http://www.oracle.com/technetwork/java/javase/downloads - keyGen.init(256); - String password = Base64.getEncoder().encodeToString(keyGen.generateKey().getEncoded()); - - // GENERATE random salt - final byte[] salt = new byte[12]; - SecureRandom random = SecureRandom.getInstanceStrong(); - random.nextBytes(salt); - - // DERIVE key (from password and salt) - SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); - // Needs unlimited strength policy files http://www.oracle.com/technetwork/java/javase/downloads - KeySpec keyspec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256); - SecretKey tmp = factory.generateSecret(keyspec); - SecretKey key = new SecretKeySpec(tmp.getEncoded(), "AES"); - - // GENERATE random nonce (number used once) - final byte[] nonce = new byte[32]; - random.nextBytes(nonce); - - // SET UP CIPHER for encryption - Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); - GCMParameterSpec spec = new GCMParameterSpec(16 * 8, nonce); - cipher.init(Cipher.ENCRYPT_MODE, key, spec); - - //byte[] aad = "Additional authenticated not encrypted data".getBytes(); - //cipher.updateAAD(aad); - - // TODO store encryption parameters as authenticated data prepended to the file content - - // SET UP OUTPUT STREAM and write content of String - try ( - FileOutputStream fileOutputStream = new FileOutputStream("encryptedFile.enc"); - CipherOutputStream encryptedOutputStream = new CipherOutputStream(fileOutputStream, cipher); - InputStream stringInputStream = new ByteArrayInputStream(plainText.getBytes(StandardCharsets.UTF_8)); - ) { - byte[] buffer = new byte[8192]; - while (stringInputStream.read(buffer) > 0) { - encryptedOutputStream.write(buffer); - } - } - - // READ ENCRYPTED FILE - StringBuilder stringBuilder = new StringBuilder(); - cipher.init(Cipher.DECRYPT_MODE, key, spec); - //cipher.updateAAD(aad); - try ( - FileInputStream fileInputStream = new FileInputStream("encryptedFile.enc"); - CipherInputStream cipherInputStream = new CipherInputStream(fileInputStream, cipher); - ) { - byte[] buffer = new byte[8192]; - while (cipherInputStream.read(buffer) > 0) { - stringBuilder.append(new String(buffer, StandardCharsets.UTF_8)); - } - } - // TODO trim() should not be needed! - String decryptedCipherText = stringBuilder.toString().trim(); - LOGGER.log(Level.INFO, decryptedCipherText); - - LOGGER.log(Level.INFO, - () -> String.format("Decrypted file content and original plain text are the same: %b", - decryptedCipherText.compareTo(plainText) == 0) - ); - } catch (NoSuchAlgorithmException | - NoSuchPaddingException | - InvalidKeyException | - InvalidParameterException | - InvalidAlgorithmParameterException | - InvalidKeySpecException | - IOException e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); - } - } - -} diff --git a/src/main/java/com/cryptoexamples/java/ExampleHash.java b/src/main/java/com/cryptoexamples/java/ExampleHash.java new file mode 100644 index 0000000..5a20e0a --- /dev/null +++ b/src/main/java/com/cryptoexamples/java/ExampleHash.java @@ -0,0 +1,48 @@ +package com.cryptoexamples.java; + + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Example for hashing of a string in one method. + * - SHA-512 + * - BASE64 encoding as representation for the byte-arrays + * - UTF-8 encoding of String + * - Exception handling + */ +public class ExampleHash { + private static final Logger LOGGER = Logger.getLogger(ExampleHash.class.getName()); + + /** + * Demonstrational method that hashes the plainText. + * @param plainText + * @return true if hashing was successful, false otherwise + */ + public static boolean demonstrateHash(String plainText) { + try { + // Get MessageDigest Instance + MessageDigest messageDigest = MessageDigest.getInstance("SHA-512"); + + // CREATE HASH + byte[] hashBytes = messageDigest.digest(plainText.getBytes(StandardCharsets.UTF_8)); + + // CONVERT/ENCODE IN BASE64 + String hashString = Base64.getEncoder().encodeToString(hashBytes); + + LOGGER.log(Level.INFO, hashString); + return true; + } catch (NoSuchAlgorithmException e) { + LOGGER.log(Level.SEVERE, e.getLocalizedMessage()); + return false; + } + } + + public static void main(String[] args) { + demonstrateHash("Text that should be authenticated by comparing the hash of it!"); + } +} diff --git a/src/main/java/com/cryptoexamples/java/ExampleHashInOneMethod.java b/src/main/java/com/cryptoexamples/java/ExampleHashInOneMethod.java deleted file mode 100644 index c3b15d7..0000000 --- a/src/main/java/com/cryptoexamples/java/ExampleHashInOneMethod.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.cryptoexamples.java; - - -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Base64; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * All in one example for hashing of a string in one method; - * Including - * - SHA-512 - * - BASE64-encoding as representation for the byte-arrays - * - UTF-8 encoding of String - * - Exception handling - */ -public class ExampleHashInOneMethod { - private static final Logger LOGGER = Logger.getLogger(ExampleHashInOneMethod.class.getName()); - - public static void main(String[] args) { - String plainText = "Text that should be authenticated by comparing the hash of it!"; - try { - // https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest - MessageDigest messageDigest = MessageDigest.getInstance("SHA-512"); - - // CREATE HASH - byte[] hash = messageDigest.digest(plainText.getBytes(StandardCharsets.UTF_8)); - - // CONVERT/ENCODE IN BASE64 - String hashString = new String(Base64.getEncoder().encode(hash),StandardCharsets.UTF_8); - - LOGGER.log(Level.INFO, hashString); - } catch (NoSuchAlgorithmException e) { - LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e); - } - } -} diff --git a/src/main/java/com/cryptoexamples/java/ExampleSignatureInOneMethod.java b/src/main/java/com/cryptoexamples/java/ExampleSignature.java similarity index 65% rename from src/main/java/com/cryptoexamples/java/ExampleSignatureInOneMethod.java rename to src/main/java/com/cryptoexamples/java/ExampleSignature.java index ddb3306..1ad54f0 100644 --- a/src/main/java/com/cryptoexamples/java/ExampleSignatureInOneMethod.java +++ b/src/main/java/com/cryptoexamples/java/ExampleSignature.java @@ -12,19 +12,22 @@ import java.util.logging.Logger; /** - * All in one example for cryptographic signing of a string in one method; - * Including + * Example for cryptographic signing of a string in one method. * - Generation of public and private RSA 4096 bit keypair * - SHA-512 with RSA - * - BASE64-encoding as representation for the byte-arrays + * - BASE64 encoding as representation for the byte-arrays * - UTF-8 encoding of String * - Exception handling */ -public class ExampleSignatureInOneMethod { - private static final Logger LOGGER = Logger.getLogger(ExampleSignatureInOneMethod.class.getName()); +public class ExampleSignature { + private static final Logger LOGGER = Logger.getLogger(ExampleSignature.class.getName()); - public static void main(String[] args) { - String plainText = "Text that should be signed to prevent unknown tampering with its content."; + /** + * Demonstrational method that signs the plainText using a newly generated keypair. + * @param plainText + * @return true if signing and verification were successful, false otherwise + */ + public static boolean demonstrateSignature(String plainText) { try { // GENERATE NEW KEYPAIR KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); @@ -38,18 +41,24 @@ public static void main(String[] args) { signature.update(plainText.getBytes(StandardCharsets.UTF_8)); // SIGN DATA/STRING - byte[] signatureForPlainText = signature.sign(); - String signatureForPlainTextString = new String(Base64.getEncoder().encode(signatureForPlainText),StandardCharsets.UTF_8); + String signatureForPlainTextString = Base64.getEncoder().encodeToString(signature.sign()); LOGGER.log(Level.INFO, () -> String.format("Signature: %s", signatureForPlainTextString)); // VERIFY JUST CREATED SIGNATURE USING PUBLIC KEY signature.initVerify(keyPair.getPublic()); signature.update(plainText.getBytes(StandardCharsets.UTF_8)); - boolean isSignatureCorrect = signature.verify(signatureForPlainText); + boolean isSignatureCorrect = signature.verify(Base64.getDecoder().decode(signatureForPlainTextString)); LOGGER.log(Level.INFO, () -> String.format("Signature is correct: %b", isSignatureCorrect)); + return isSignatureCorrect; } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { - LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e); + LOGGER.log(Level.SEVERE, e.getLocalizedMessage()); + return false; } } + + public static void main(String[] args) { + demonstrateSignature("Text that should be signed to prevent unknown tampering with its content."); + + } } diff --git a/src/main/java/com/cryptoexamples/java/ExampleStringEncryptionKeyBasedInOneMethod.java b/src/main/java/com/cryptoexamples/java/ExampleStringEncryptionKeyBased.java similarity index 62% rename from src/main/java/com/cryptoexamples/java/ExampleStringEncryptionKeyBasedInOneMethod.java rename to src/main/java/com/cryptoexamples/java/ExampleStringEncryptionKeyBased.java index 5c8cfc9..749c9a8 100644 --- a/src/main/java/com/cryptoexamples/java/ExampleStringEncryptionKeyBasedInOneMethod.java +++ b/src/main/java/com/cryptoexamples/java/ExampleStringEncryptionKeyBased.java @@ -7,6 +7,7 @@ import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.GCMParameterSpec; +import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.InvalidParameterException; @@ -17,23 +18,26 @@ import java.util.logging.Logger; /** - * All in one example for encryption and decryption of a string in one method; - * Including + * Example for encryption and decryption of a string in one method. * - Random key generation using strong secure random number generator * - AES-256 authenticated encryption using GCM - * - BASE64-encoding as representation for the byte-arrays + * - BASE64 encoding as representation for the byte-arrays + * - UTF-8 encoding of Strings * - Exception handling */ -public class ExampleStringEncryptionKeyBasedInOneMethod { - private static final Logger LOGGER = Logger.getLogger(ExampleStringEncryptionKeyBasedInOneMethod.class.getName()); +public class ExampleStringEncryptionKeyBased { + private static final Logger LOGGER = Logger.getLogger(ExampleStringEncryptionKeyBased.class.getName()); - public static void main(String[] args) { - String plainText = "Text that is going to be sent over an insecure channel and must be encrypted at all costs!"; + /** + * Demonstrational method that encrypts the plainText using a newly generated key. + * @param plainText + * @return true if encryption and decryption were successful, false otherwise + */ + public static boolean demonstrateKeyBasedSymmetricEncryption(String plainText) { try { // GENERATE key - // TODO key should only be generated once and then stored in a secure location. + // TODO key should only be generated once and then managed with a key manager/key store. KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - // 256 bit requires unlimited strength policy files http://www.oracle.com/technetwork/java/javase/downloads keyGen.init(256); SecretKey key = keyGen.generateKey(); @@ -47,22 +51,24 @@ public static void main(String[] args) { GCMParameterSpec spec = new GCMParameterSpec(16 * 8, nonce); cipher.init(Cipher.ENCRYPT_MODE, key, spec); - //byte[] aad = "Additional authenticated not encrypted data".getBytes(); - //cipher.updateAAD(aad); - - byte[] byteCipher = cipher.doFinal(plainText.getBytes()); + byte[] byteCipher = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); // CONVERSION of raw bytes to BASE64 representation - String cipherText = new String(Base64.getEncoder().encode(byteCipher)); + String cipherText = Base64.getEncoder().encodeToString(byteCipher); // DECRYPTION cipher.init(Cipher.DECRYPT_MODE, key, spec); - //cipher.updateAAD(aad); byte[] decryptedCipher = cipher.doFinal(Base64.getDecoder().decode(cipherText)); - String decryptedCipherText = new String(decryptedCipher); + String decryptedCipherText = new String(decryptedCipher, StandardCharsets.UTF_8); LOGGER.log(Level.INFO, () -> String.format("Decrypted and original plain text are the same: %b", decryptedCipherText.compareTo(plainText) == 0)); + return decryptedCipherText.compareTo(plainText) == 0; } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | InvalidParameterException | InvalidAlgorithmParameterException e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); + LOGGER.log(Level.SEVERE, e.getLocalizedMessage()); + return false; } } + + public static void main(String[] args) { + demonstrateKeyBasedSymmetricEncryption("Text that is going to be sent over an insecure channel and must be encrypted at all costs!"); + } } diff --git a/src/main/java/com/cryptoexamples/java/ExampleStringEncryptionPasswordBasedInOneMethod.java b/src/main/java/com/cryptoexamples/java/ExampleStringEncryptionPasswordBased.java similarity index 52% rename from src/main/java/com/cryptoexamples/java/ExampleStringEncryptionPasswordBasedInOneMethod.java rename to src/main/java/com/cryptoexamples/java/ExampleStringEncryptionPasswordBased.java index 7455b6b..666aff9 100644 --- a/src/main/java/com/cryptoexamples/java/ExampleStringEncryptionPasswordBasedInOneMethod.java +++ b/src/main/java/com/cryptoexamples/java/ExampleStringEncryptionPasswordBased.java @@ -10,6 +10,7 @@ import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.InvalidParameterException; @@ -22,39 +23,43 @@ import java.util.logging.Logger; /** - * All in one example for encryption and decryption of a string in one method; - * Including + * Example for encryption and decryption of a string in one method. * - Random password generation using strong secure random number generator * - Random salt generation - * - Key derivation using PBKDF2 HMAC SHA-256, + * - Key derivation using PBKDF2 HMAC SHA-512, * - AES-256 authenticated encryption using GCM - * - BASE64-encoding as representation for the byte-arrays + * - BASE64 encoding as representation for the byte-arrays + * - UTF-8 encoding of Strings * - Exception handling */ -public class ExampleStringEncryptionPasswordBasedInOneMethod { - private static final Logger LOGGER = Logger.getLogger(ExampleStringEncryptionPasswordBasedInOneMethod.class.getName()); +public class ExampleStringEncryptionPasswordBased { + private static final Logger LOGGER = Logger.getLogger(ExampleStringEncryptionPasswordBased.class.getName()); - public static void main(String[] args) { - String plainText = "Text that is going to be sent over an insecure channel and must be encrypted at all costs!"; + /** + * Demonstrational method that encrypts the plainText using a password (that is used to derive the required key). + * @param plainText + * @param password + * @return true if encryption and decryption were successful, false otherwise + */ + public static boolean demonstratePasswordBasedSymmetricEncryption(String plainText, String password) { try { // GENERATE password (not needed if you have a password already) - KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - // Needs unlimited strength policy files http://www.oracle.com/technetwork/java/javase/downloads - keyGen.init(256); - String password = Base64.getEncoder().encodeToString(keyGen.generateKey().getEncoded()); + if(password == null || password.isEmpty()) { + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + password = Base64.getEncoder().encodeToString(keyGen.generateKey().getEncoded()); + } // GENERATE random salt (needed for PBKDF2) - final byte[] salt = new byte[12]; + final byte[] salt = new byte[64]; SecureRandom random = SecureRandom.getInstanceStrong(); random.nextBytes(salt); // DERIVE key (from password and salt) - SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); - // Needs unlimited strength policy files http://www.oracle.com/technetwork/java/javase/downloads - KeySpec keyspec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256); - SecretKey tmp = factory.generateSecret(keyspec); - SecretKey key = new SecretKeySpec(tmp.getEncoded(), "AES"); - + SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512"); + KeySpec passwordBasedEncryptionKeySpec = new PBEKeySpec(password.toCharArray(), salt, 10000, 256); + SecretKey secretKeyFromPBKDF2 = secretKeyFactory.generateSecret(passwordBasedEncryptionKeySpec); + SecretKey key = new SecretKeySpec(secretKeyFromPBKDF2.getEncoded(), "AES"); // GENERATE random nonce (number used once) final byte[] nonce = new byte[32]; @@ -65,23 +70,25 @@ public static void main(String[] args) { GCMParameterSpec spec = new GCMParameterSpec(16 * 8, nonce); cipher.init(Cipher.ENCRYPT_MODE, key, spec); - //byte[] aad = "Additional authenticated not encrypted data".getBytes(); - //cipher.updateAAD(aad); - - byte[] byteCipher = cipher.doFinal(plainText.getBytes()); + byte[] cipherTextBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); // CONVERSION of raw bytes to BASE64 representation - String cipherText = new String(Base64.getEncoder().encode(byteCipher)); + String cipherText = Base64.getEncoder().encodeToString(cipherTextBytes); // DECRYPTION cipher.init(Cipher.DECRYPT_MODE, key, spec); - //cipher.updateAAD(aad); - byte[] decryptedCipher = cipher.doFinal(Base64.getDecoder().decode(cipherText)); - String decryptedCipherText = new String(decryptedCipher); + byte[] decryptedCipherTextBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText)); + String decryptedCipherText = new String(decryptedCipherTextBytes, StandardCharsets.UTF_8); LOGGER.log(Level.INFO, () -> String.format("Decrypted and original plain text are the same: %b", decryptedCipherText.compareTo(plainText) == 0)); + return decryptedCipherText.compareTo(plainText) == 0; } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | InvalidParameterException | InvalidAlgorithmParameterException | InvalidKeySpecException e) { - LOGGER.log(Level.SEVERE, e.getMessage(), e); + LOGGER.log(Level.SEVERE, e.getLocalizedMessage()); + return false; } } + public static void main(String[] args) { + demonstratePasswordBasedSymmetricEncryption("Text that is going to be sent over an insecure channel and must be encrypted at all costs!",null); + } + } diff --git a/src/test/java/com/cryptoexamples/java/EncryptedFileTest.java b/src/test/java/com/cryptoexamples/java/EncryptedFileTest.java deleted file mode 100644 index 0173762..0000000 --- a/src/test/java/com/cryptoexamples/java/EncryptedFileTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.cryptoexamples.java; - -import org.junit.Test; - -import java.security.GeneralSecurityException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - - -/** - * Created by Kai on 12.04.2017. - */ -public class EncryptedFileTest { - - - public void setUp() { - - } - - - public void tearDown() { - - } - - @Test - public void testEncryptAndDecryptWithUmlaut() { - try { - String password = EncryptedString.generatePassword(32); - String testString = "Die heiße Zypernsonne quälte Max und Victoria ja böse auf dem Weg bis zur Küste"; - String path = "encryptedFile.enc"; - EncryptedFile encryptedFile = new EncryptedFile(); - encryptedFile.encrypt(testString,password,path); - - assertEquals(testString, new EncryptedFile().decrypt(password, path)); - } catch (GeneralSecurityException e) { - assertTrue(false); - } - } - - @Test - public void testEncryptAndDecryptWithASCII() { - try { - String password = EncryptedString.generatePassword(32); - String testString = "A quick movement of the enemy will jeopardize six gunboats."; - String path = "encryptedFile.enc"; - EncryptedFile encryptedFile = new EncryptedFile(); - encryptedFile.encrypt(testString,password,path); - - assertEquals(testString, new EncryptedFile().decrypt(password, path)); - } catch (GeneralSecurityException e) { - assertTrue(false); - } - } -} diff --git a/src/test/java/com/cryptoexamples/java/EncryptedStringTest.java b/src/test/java/com/cryptoexamples/java/EncryptedStringTest.java deleted file mode 100644 index 96aed10..0000000 --- a/src/test/java/com/cryptoexamples/java/EncryptedStringTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.cryptoexamples.java; - -import com.cryptoexamples.java.EncryptedString; -import org.junit.Test; - -import java.security.GeneralSecurityException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - - -/** - * Created by Kai on 12.04.2017. - */ -public class EncryptedStringTest { - - - public void setUp() { - - } - - - public void tearDown() { - - } - - @Test - public void testEncryptAndDecryptWithUmlaut() { - try { - String password = EncryptedString.generatePassword(32); - String testString = "Die heiße Zypernsonne quälte Max und Victoria ja böse auf dem Weg bis zur Küste"; - EncryptedString encryptedString = new EncryptedString().encrypt(testString, password); - assertEquals(testString, encryptedString.decrypt(password)); - } catch (GeneralSecurityException e) { - assertTrue(false); - } - } - - @Test - public void testEncryptAndDecryptWithASCII() { - try { - String password = EncryptedString.generatePassword(32); - String testString = "A quick movement of the enemy will jeopardize six gunboats."; - EncryptedString encryptedString = new EncryptedString().encrypt(testString, password); - assertEquals(testString, encryptedString.decrypt(password)); - } catch (GeneralSecurityException e) { - assertTrue(false); - } - } -} diff --git a/src/test/java/com/cryptoexamples/java/EncryptionInOneMethodTests.java b/src/test/java/com/cryptoexamples/java/EncryptionInOneMethodTests.java index ffc715e..a023870 100644 --- a/src/test/java/com/cryptoexamples/java/EncryptionInOneMethodTests.java +++ b/src/test/java/com/cryptoexamples/java/EncryptionInOneMethodTests.java @@ -3,10 +3,12 @@ import org.junit.*; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.PrintStream; import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; /** @@ -35,33 +37,54 @@ public void resetOut() { } @Test - public void testStringEncryptionPasswordBasedMain() { - ExampleStringEncryptionPasswordBasedInOneMethod.main(new String[1]); + public void testStringEncryptionPasswordBased() throws IOException { + ExampleStringEncryptionPasswordBased.main(new String[1]); + assertThat(errContent.toString(), containsString("Decrypted and original plain text are the same: true")); + errContent.flush(); + assertTrue(ExampleStringEncryptionPasswordBased.demonstratePasswordBasedSymmetricEncryption("plaintext",null)); assertThat(errContent.toString(), containsString("Decrypted and original plain text are the same: true")); } @Test - public void testStringEncryptionKeyBasedMain() { - ExampleStringEncryptionKeyBasedInOneMethod.main(new String[1]); + public void testStringEncryptionKeyBased() throws IOException { + ExampleStringEncryptionKeyBased.main(new String[1]); + assertThat(errContent.toString(), containsString("Decrypted and original plain text are the same: true")); + errContent.flush(); + assertTrue(ExampleStringEncryptionKeyBased.demonstrateKeyBasedSymmetricEncryption("plaintext")); assertThat(errContent.toString(), containsString("Decrypted and original plain text are the same: true")); } @Test - public void testFileEncryptionMain() { - ExampleFileEncryptionInOneMethod.main(new String[1]); + public void testAsymmetricStringEncryption() { + ExampleAsymmetricStringEncryption.main(new String[1]); + assertThat(errContent.toString(), containsString("Decrypted and original plain text are the same: true")); + } + + @Test + public void testFileEncryption() throws IOException { + ExampleFileEncryption.main(new String[1]); + assertThat(errContent.toString(), containsString("Decrypted file content and original plain text are the same: true")); + errContent.flush(); + assertTrue(ExampleFileEncryption.demonstrateFileEncryption("file.enc", "plaintext", null)); assertThat(errContent.toString(), containsString("Decrypted file content and original plain text are the same: true")); } @Test - public void testHashMain() { - ExampleHashInOneMethod.main(new String[1]); + public void testHash() throws IOException { + ExampleHash.main(new String[1]); // uses string: "Text that should be authenticated by comparing the hash of it!" assertThat(errContent.toString(), containsString("jg0X629+SmdP0/LTHZV/3zXBrizM3/hptRZVIuTXSCtyaqAe0NB8KMld2qebBIXFS1yowCUpCPu93l/fPmKEXg==")); + errContent.flush(); + assertTrue(ExampleHash.demonstrateHash("plaintext")); + assertThat(errContent.toString(), containsString("jg0X629+SmdP0/LTHZV/3zXBrizM3/hptRZVIuTXSCtyaqAe0NB8KMld2qebBIXFS1yowCUpCPu93l/fPmKEXg==")); } @Test - public void testSignatureMain() { - ExampleSignatureInOneMethod.main(new String[1]); + public void testSignature() throws IOException { + ExampleSignature.main(new String[1]); + assertThat(errContent.toString(), containsString("Signature is correct: true")); + errContent.flush(); + assertTrue(ExampleSignature.demonstrateSignature("plainText")); assertThat(errContent.toString(), containsString("Signature is correct: true")); }