From a87e6763bc88db30ebb52f910b66f6309e19ad6d Mon Sep 17 00:00:00 2001 From: HealthPDU Date: Mon, 15 Jun 2020 15:42:27 +0000 Subject: [PATCH] new release v1.5.3 --- .gitlab-ci.yml | 3 + Jenkinsfile | 11 - checkstyle/checkstyle-suppressions.xml | 9 + pom.xml | 318 ++++++++++-------- .../java/uk/gov/dwp/crypto/SecureStrings.java | 204 ++++++----- .../uk/gov/dwp/crypto/SecureStringsTest.java | 165 ++++----- .../dwp/crypto/TestClassForSerialisation.java | 66 ++-- 7 files changed, 406 insertions(+), 370 deletions(-) create mode 100644 .gitlab-ci.yml delete mode 100644 Jenkinsfile create mode 100644 checkstyle/checkstyle-suppressions.xml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..abea01b --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,3 @@ +include: + - project: 'health-pdu/htds/pipeline/ci-scripts' + file: 'maven-base.yml' diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index cf8247f..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,11 +0,0 @@ -node { - checkout scm - - buildJava { - isComponent = true - - buildGoals = [ - "org.jacoco:jacoco-maven-plugin:prepare-agent" - ] - } -} diff --git a/checkstyle/checkstyle-suppressions.xml b/checkstyle/checkstyle-suppressions.xml new file mode 100644 index 0000000..4de3b9c --- /dev/null +++ b/checkstyle/checkstyle-suppressions.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/pom.xml b/pom.xml index 5e95e57..3e1978e 100755 --- a/pom.xml +++ b/pom.xml @@ -1,155 +1,185 @@ - 4.0.0 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - uk.gov.dwp.crypto - secure-strings - 1.5.2 + uk.gov.dwp.crypto + secure-strings + 1.5.3 - ${project.groupId}:${project.artifactId} - Utility for storing passwords in memory encrypted form to prevent heap inspection - https://github.com/dwp/secure-strings + ${project.groupId}:${project.artifactId} + Utility for storing passwords in memory encrypted form to prevent heap inspection + + https://github.com/dwp/secure-strings - - - MIT License - repo - http://www.opensource.org/licenses/mit-license.php - - + + + MIT License + repo + http://www.opensource.org/licenses/mit-license.php + + - - - Andrew Valentine - DWP - andrew.valentine@dwp.gsi.gov.uk - http://www.gov.uk/dwp - - - Chris Hulley - DWP - chris.hulley@dwp.gsi.gov.uk - http://www.gov.uk/dwp - - + + + Andrew Valentine + DWP + andrew.valentine@dwp.gov.uk + http://www.gov.uk/dwp + + + Chris Hulley + DWP + chris.hulley@dwp.gov.uk + http://www.gov.uk/dwp + + - - scm:git:git://github.com/dwp/secure-strings.git - scm:git:ssh://github.com:dwp/secure-strings.git - https://github.com/dwp/secure-strings - + + scm:git:git://github.com/dwp/secure-strings.git + scm:git:ssh://github.com:dwp/secure-strings.git + https://github.com/dwp/secure-strings + - - UTF-8 - 2.10.0 - 1.8 - 1.8 - 2.10.4 - 3.0.1 - 1.6 - 1.7.25 - 4.0.2 - 4.12 - 1.8 - + + UTF-8 + 3.8.1 + 2.10.0 + 3.2.0 + 3.0.1 + 1.6 + 0.8.5 + 1.7.25 + 5.3.0 + 4.12 + 11 + - - - com.fasterxml.jackson.core - jackson-databind - ${jackson-data.version} - - - org.slf4j - slf4j-api - ${slf4j.version} - - - org.slf4j - slf4j-log4j12 - ${slf4j.version} - test - - - junit - junit - ${junit.version} - test - - + + + com.fasterxml.jackson.core + jackson-databind + ${jackson-data.version} + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + slf4j-log4j12 + ${slf4j.version} + test + + + junit + junit + ${junit.version} + test + + - - - - . - META-INF - - LICENSE - README.md - CONTRIBUTING.md - - - - - - org.owasp - dependency-check-maven - ${owasp.version} - - 12 - 4 - src/test/resources/DependencySuppression.xml - - - - - check - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - ${mvn-javadoc.version} - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-source-plugin - ${mvn-source.version} - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-gpg-plugin - ${mvn-gpg.version} - - - sign-artifacts - verify - - sign - - - - - - + + + + . + META-INF + + LICENSE + README.md + CONTRIBUTING.md + + + + + + org.owasp + dependency-check-maven + ${owasp.version} + + 12 + 4 + src/test/resources/DependencySuppression.xml + + + + + check + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + jacoco-initialize + + prepare-agent + + + + jacoco-complete + verify + + report + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${mvn-javadoc.version} + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + ${mvn-source.version} + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + ${mvn-gpg.version} + + + sign-artifacts + verify + + sign + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.version} + + ${java.version} + ${java.version} + + + + diff --git a/src/main/java/uk/gov/dwp/crypto/SecureStrings.java b/src/main/java/uk/gov/dwp/crypto/SecureStrings.java index ec1ec5f..38e1250 100755 --- a/src/main/java/uk/gov/dwp/crypto/SecureStrings.java +++ b/src/main/java/uk/gov/dwp/crypto/SecureStrings.java @@ -19,118 +19,114 @@ import java.security.NoSuchAlgorithmException; public class SecureStrings { - private static final Logger LOGGER = LoggerFactory.getLogger(SecureStrings.class.getName()); - private Cipher cipherEncrypt = null; - private Cipher cipherDecrypt = null; + private static final Logger LOGGER = LoggerFactory.getLogger(SecureStrings.class.getName()); + private Cipher cipherEncrypt = null; + private Cipher cipherDecrypt = null; - /** - * Default constructor. - * Assumes AES encryption, generates a key and sets up the internal ciphers - */ - public SecureStrings() { - try { - initialiseCiphers("AES"); - } catch (NoSuchAlgorithmException e) { - LOGGER.error(String.format("initialiseCiphers error : %s", e.getMessage())); - LOGGER.debug(e.getMessage(), e); - } - } + /** + * Default constructor. Assumes AES encryption, generates a key and sets up the internal ciphers + */ + public SecureStrings() + throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { + initialiseCiphers("AES"); + } - /** - * Overloaded constructor - * Takes in crypto Type, generates a key and sets up the internal ciphers - * - * @param cryptoType a string to match the cryptotype used for key generation and cipher generation - * @throws NoSuchAlgorithmException - if the input string is not a valid crypto type. - */ - public SecureStrings(String cryptoType) throws NoSuchAlgorithmException { - initialiseCiphers(cryptoType); - } + /** + * Overloaded constructor Takes in crypto Type, generates a key and sets up the internal ciphers. + * + * @param cryptoType - string cryptography type (eg AES) + * @throws NoSuchAlgorithmException - if the input string is not a valid crypto type + * @throws InvalidKeyException - if the input string is not a valid crypto type + * @throws NoSuchPaddingException - if the input string is not a valid crypto type + */ + public SecureStrings(String cryptoType) + throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException { + initialiseCiphers(cryptoType); + } - /** - * initialiseCiphers - * Takes in crypto Type, generates a key and sets up the internal ciphers - * - * @param cryptoType a string to match the cryptotype used for key generation and cipher generation - * @throws NoSuchAlgorithmException - if the input string is not a valid crypto type. - */ - private void initialiseCiphers(String cryptoType) throws NoSuchAlgorithmException { - if ((null == cipherEncrypt) || (null == cipherDecrypt)) { - try { - Key tempKey = KeyGenerator.getInstance(cryptoType).generateKey(); - cipherEncrypt = Cipher.getInstance(cryptoType); - cipherDecrypt = Cipher.getInstance(cryptoType); - cipherEncrypt.init(Cipher.ENCRYPT_MODE, tempKey); - cipherDecrypt.init(Cipher.DECRYPT_MODE, tempKey); - } catch (NoSuchPaddingException | InvalidKeyException e) { - LOGGER.error(String.format("initialiseCiphers object error : %s", e.getMessage())); - LOGGER.debug(e.getMessage(), e); - } - } - } + /** + * initialiseCiphers Takes in crypto Type, generates a key and sets up the internal ciphers. + * + * @param cryptoType - string cryptography type (eg AES) + * @throws NoSuchAlgorithmException - if the input string is not a valid crypto type + * @throws NoSuchPaddingException - if the input string is not a valid crypto type + * @throws InvalidKeyException - if the input string is not a valid crypto type + */ + private void initialiseCiphers(String cryptoType) + throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { + cipherEncrypt = Cipher.getInstance(cryptoType); + cipherDecrypt = Cipher.getInstance(cryptoType); - /** - * sealString - * Takes a string and seals it within a SealedObject using the auto-generated ciphers. - * - * @param input the string to encapsulate within the returned SealedObject - * @return SealedObject Object containing encrypted input, null on error - */ - public SealedObject sealString(String input) { - SealedObject returnValue = null; - try { - returnValue = new SealedObject(input, cipherEncrypt); - } catch (IOException | IllegalBlockSizeException e) { - LOGGER.error(String.format("error sealing input : %s", e.getMessage())); - LOGGER.debug(e.getMessage(), e); - } - return returnValue; - } + Key tempKey = KeyGenerator.getInstance(cryptoType).generateKey(); + cipherEncrypt.init(Cipher.ENCRYPT_MODE, tempKey); + cipherDecrypt.init(Cipher.DECRYPT_MODE, tempKey); + } - /** - * revealString - * Uses the auto generated ciphers to retrieve a string from the SealedObject. - * - * @param inputObject object containing a string to return. - * For success, must be generated by a call to sealString in the same SecureStrings instance. - * @return String, null on error. - */ - public String revealString(SealedObject inputObject) { - if (null != inputObject) try { - return (String) inputObject.getObject(cipherDecrypt); //using cast to allow for null string input - } catch (IOException | BadPaddingException | IllegalBlockSizeException | ClassNotFoundException e) { - LOGGER.error(String.format("error unsealing string : %s", e.getMessage())); - LOGGER.debug(e.getMessage(), e); - } - return null; + /** + * sealString Takes a string and seals it within a SealedObject using the auto-generated ciphers. + * + * @param input the string to encapsulate within the returned SealedObject + * @return SealedObject Object containing encrypted input + * @throws IOException - if an error occurs during serialization + * @throws IllegalBlockSizeException if the given cipher is a block cipher, no padding has been + * requested, and the total input length (i.e., the length of the serialized object contents) + * is not a multiple of the cipher's block size + */ + public SealedObject sealString(String input) throws IOException, IllegalBlockSizeException { + return new SealedObject(input, cipherEncrypt); + } + + /** + * revealString Uses the auto generated ciphers to retrieve a string from the SealedObject. + * + * @param inputObject object containing a string to return. For success, must be generated by a + * call to sealString in the same SecureStrings instance. + * @return String, null on error. + */ + public String revealString(SealedObject inputObject) { + if (null != inputObject) { + try { + return (String) + inputObject.getObject(cipherDecrypt); // using cast to allow for null string input + } catch (IOException + | BadPaddingException + | IllegalBlockSizeException + | ClassNotFoundException e) { + LOGGER.error(String.format("error unsealing string : %s", e.getMessage())); + LOGGER.debug(e.getMessage(), e); + } } - public static T escapedJSONObjectFromString(String inputString, Class type) throws IOException { - T returnValue; - if (inputString != null && inputString.trim().length() != 0) { - final CharacterEscapes jsonCharacterEscapes = generateJSONCharacterEscapes(); - final ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.getFactory().setCharacterEscapes(jsonCharacterEscapes); - returnValue = objectMapper.readValue(inputString, type); - } else { - throw new InvalidParameterException("A JSON payload must be specified"); - } - return returnValue; + return null; + } + + public static T escapedJSONObjectFromString(String inputString, Class type) + throws IOException { + T returnValue; + if (inputString != null && inputString.trim().length() != 0) { + final CharacterEscapes jsonCharacterEscapes = generateJSONCharacterEscapes(); + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.getFactory().setCharacterEscapes(jsonCharacterEscapes); + returnValue = objectMapper.readValue(inputString, type); + } else { + throw new InvalidParameterException("A JSON payload must be specified"); } + return returnValue; + } - private static CharacterEscapes generateJSONCharacterEscapes() { - return new CharacterEscapes() { - private static final long serialVersionUID = 11L; + private static CharacterEscapes generateJSONCharacterEscapes() { + return new CharacterEscapes() { + private static final long serialVersionUID = 11L; - @Override - public int[] getEscapeCodesForAscii() { - return standardAsciiEscapesForJSON(); - } + @Override + public int[] getEscapeCodesForAscii() { + return standardAsciiEscapesForJSON(); + } - @Override - public SerializableString getEscapeSequence(final int ch) { - return null; - } - }; - } -} \ No newline at end of file + @Override + public SerializableString getEscapeSequence(final int ch) { + return null; + } + }; + } +} diff --git a/src/test/java/uk/gov/dwp/crypto/SecureStringsTest.java b/src/test/java/uk/gov/dwp/crypto/SecureStringsTest.java index 643e7e3..74f4de1 100755 --- a/src/test/java/uk/gov/dwp/crypto/SecureStringsTest.java +++ b/src/test/java/uk/gov/dwp/crypto/SecureStringsTest.java @@ -1,6 +1,9 @@ package uk.gov.dwp.crypto; import com.fasterxml.jackson.core.JsonParseException; +import java.security.InvalidKeyException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; import org.junit.Before; import org.junit.Test; @@ -10,85 +13,91 @@ import java.security.NoSuchAlgorithmException; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public class SecureStringsTest { - private SecureStrings localSecureString; - private SealedObject anObject; - - @Before - public void setUp() { - localSecureString = new SecureStrings(); - anObject = null; - } - - @Test - public void test_SealString() throws Exception { - assertTrue(localSecureString.sealString("APassword") != null); - } - - @Test - public void test_RevealString() throws Exception { - anObject = localSecureString.sealString("Test Password"); - assertTrue(localSecureString.revealString(anObject).equals("Test Password")); - } - - @Test - public void test_RevealString_Null_Object() throws Exception { - assertTrue(localSecureString.revealString(null) == null); - } - - @Test - public void test_SealString_Null_String() throws Exception { - assertTrue(localSecureString.sealString(null) != null); - } - - @Test - public void test_RevealString_Wrong_Object() throws Exception { - SecureStrings testSecureString = new SecureStrings(); - anObject = testSecureString.sealString("Test Password"); - assertTrue(localSecureString.revealString(anObject) == null); - } - - @Test(expected = NoSuchAlgorithmException.class) - public void test_To_Validate_Constructor_With_Invalid_Crypto_Type() throws NoSuchAlgorithmException { - new SecureStrings("Bob"); - } - - @Test - public void test_Storing_String_As_Null_Can_Be_Decrypted() { - anObject = localSecureString.sealString(null); - assertTrue("This should return null", localSecureString.revealString(anObject) == null); - } - - @Test - public void test_For_escapeJSONObject_With_Valid_JSON_String() throws IOException { - String testJsonString = "{" + - "\"testBoolean\":true," + - "\"testString\":\"string\"," + - "\"testInteger\":42" + - "}"; - TestClassForSerialisation testing = SecureStrings.escapedJSONObjectFromString(testJsonString, TestClassForSerialisation.class); - assertThat(testing.isTestBoolean(), is(true)); - assertThat(testing.getTestString(), containsString("string")); - assertThat(testing.getTestInteger(), is(42)); - } - - @Test (expected = JsonParseException.class) - public void test_For_escapeJSONObject_With_Invalid_JSON_String() throws IOException { - String testJsonString = "{" + - "\"testBoolean\":true," + - "}"; - TestClassForSerialisation testing = SecureStrings.escapedJSONObjectFromString(testJsonString, TestClassForSerialisation.class); - throw new AssertionError("Should never get here!"); - } - - @Test (expected = InvalidParameterException.class) - public void test_For_escapeJSONObject_With_Blank_JSON_String() throws IOException { - String testJsonString = ""; - TestClassForSerialisation testing = SecureStrings.escapedJSONObjectFromString(testJsonString, TestClassForSerialisation.class); - throw new AssertionError("Should never get here!"); - } -} \ No newline at end of file + private static final String TEST_STRING = "i-am-a-string-to-seal"; + private SecureStrings classInstance; + private SealedObject sealedObject; + + @Before + public void setUp() throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { + classInstance = new SecureStrings(); + sealedObject = null; + } + + @Test + public void testSealString() throws IOException, IllegalBlockSizeException { + assertNotNull(classInstance.sealString("APassword")); + } + + @Test + public void testRevealString() throws IOException, IllegalBlockSizeException { + sealedObject = classInstance.sealString(TEST_STRING); + assertThat(classInstance.revealString(sealedObject), is(equalTo(TEST_STRING))); + } + + @Test + public void testRevealstringNullObject() { + assertNull(classInstance.revealString(null)); + } + + @Test + public void testSealStringNullString() throws IOException, IllegalBlockSizeException { + assertNotNull(classInstance.sealString(null)); + } + + @Test + public void testRevealStringWrongObject() + throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IOException, + IllegalBlockSizeException { + SecureStrings localInstance = new SecureStrings(); + sealedObject = localInstance.sealString(TEST_STRING); + assertNull(classInstance.revealString(sealedObject)); + } + + @Test(expected = NoSuchAlgorithmException.class) + public void testToValidateConstructorWithInvalidCryptoType() + throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { + new SecureStrings("Bob"); + } + + @Test + public void testStoringStringAsNullCanBeDecrypted() + throws IOException, IllegalBlockSizeException { + sealedObject = classInstance.sealString(null); + assertNull("This should return null", classInstance.revealString(sealedObject)); + } + + @Test + public void testForEscapeJsonObjectWithValidJsonString() throws IOException { + String testJsonString = + "{" + "\"testBoolean\":true," + "\"testString\":\"string\"," + "\"testInteger\":42" + "}"; + TestClassForSerialisation testing = + SecureStrings.escapedJSONObjectFromString(testJsonString, TestClassForSerialisation.class); + assertThat(testing.isTestBoolean(), is(true)); + assertThat(testing.getTestString(), containsString("string")); + assertThat(testing.getTestInteger(), is(42)); + } + + @Test(expected = JsonParseException.class) + public void testForEscapeJsonObjectWithInvalidJsonString() throws IOException { + String testJsonString = "{" + "\"testBoolean\":true," + "}"; + + SecureStrings.escapedJSONObjectFromString(testJsonString, TestClassForSerialisation.class); + fail("Should have thrown a JsonParseException"); + } + + @Test(expected = InvalidParameterException.class) + public void testForEscapejsonobjectWithBlankJsonString() throws IOException { + String testJsonString = ""; + + SecureStrings.escapedJSONObjectFromString(testJsonString, TestClassForSerialisation.class); + fail("Should have thrown a InvalidParameterException"); + } +} diff --git a/src/test/java/uk/gov/dwp/crypto/TestClassForSerialisation.java b/src/test/java/uk/gov/dwp/crypto/TestClassForSerialisation.java index 1902980..bd40ea1 100755 --- a/src/test/java/uk/gov/dwp/crypto/TestClassForSerialisation.java +++ b/src/test/java/uk/gov/dwp/crypto/TestClassForSerialisation.java @@ -1,37 +1,37 @@ package uk.gov.dwp.crypto; public class TestClassForSerialisation { - private int testInteger; - private String testString; - private boolean testBoolean; - - public TestClassForSerialisation(){ - setTestBoolean(false); - setTestInteger(0); - setTestString(""); - } - - public int getTestInteger() { - return testInteger; - } - - public void setTestInteger(int testInteger) { - this.testInteger = testInteger; - } - - public String getTestString() { - return testString; - } - - public void setTestString(String testString) { - this.testString = testString; - } - - public boolean isTestBoolean() { - return testBoolean; - } - - public void setTestBoolean(boolean testBoolean) { - this.testBoolean = testBoolean; - } + private int testInteger; + private String testString; + private boolean testBoolean; + + public TestClassForSerialisation() { + setTestBoolean(false); + setTestInteger(0); + setTestString(""); + } + + int getTestInteger() { + return testInteger; + } + + void setTestInteger(int testInteger) { + this.testInteger = testInteger; + } + + String getTestString() { + return testString; + } + + void setTestString(String testString) { + this.testString = testString; + } + + boolean isTestBoolean() { + return testBoolean; + } + + void setTestBoolean(boolean testBoolean) { + this.testBoolean = testBoolean; + } }