You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AesCipherTest.java 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2020 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.api.config.internal;
  21. import java.io.File;
  22. import java.net.URL;
  23. import java.security.InvalidKeyException;
  24. import java.security.Key;
  25. import javax.crypto.BadPaddingException;
  26. import org.apache.commons.codec.binary.Base64;
  27. import org.apache.commons.lang.StringUtils;
  28. import org.junit.Rule;
  29. import org.junit.Test;
  30. import org.junit.rules.ExpectedException;
  31. import static org.assertj.core.api.Assertions.assertThat;
  32. import static org.junit.Assert.fail;
  33. public class AesCipherTest {
  34. @Rule
  35. public ExpectedException thrown = ExpectedException.none();
  36. @Test
  37. public void generateRandomSecretKey() {
  38. AesCipher cipher = new AesCipher(null);
  39. String key = cipher.generateRandomSecretKey();
  40. assertThat(StringUtils.isNotBlank(key)).isTrue();
  41. assertThat(Base64.isArrayByteBase64(key.getBytes())).isTrue();
  42. }
  43. @Test
  44. public void encrypt() throws Exception {
  45. AesCipher cipher = new AesCipher(pathToSecretKey());
  46. String encryptedText = cipher.encrypt("this is a secret");
  47. assertThat(StringUtils.isNotBlank(encryptedText)).isTrue();
  48. assertThat(Base64.isArrayByteBase64(encryptedText.getBytes())).isTrue();
  49. }
  50. @Test
  51. public void encrypt_bad_key() throws Exception {
  52. thrown.expect(RuntimeException.class);
  53. thrown.expectMessage("Invalid AES key");
  54. URL resource = getClass().getResource("/org/sonar/api/config/internal/AesCipherTest/bad_secret_key.txt");
  55. AesCipher cipher = new AesCipher(new File(resource.toURI()).getCanonicalPath());
  56. cipher.encrypt("this is a secret");
  57. }
  58. @Test
  59. public void decrypt() throws Exception {
  60. AesCipher cipher = new AesCipher(pathToSecretKey());
  61. // the following value has been encrypted with the key /org/sonar/api/config/internal/AesCipherTest/aes_secret_key.txt
  62. String clearText = cipher.decrypt("9mx5Zq4JVyjeChTcVjEide4kWCwusFl7P2dSVXtg9IY=");
  63. assertThat(clearText).isEqualTo("this is a secret");
  64. }
  65. @Test
  66. public void decrypt_bad_key() throws Exception {
  67. URL resource = getClass().getResource("/org/sonar/api/config/internal/AesCipherTest/bad_secret_key.txt");
  68. AesCipher cipher = new AesCipher(new File(resource.toURI()).getCanonicalPath());
  69. try {
  70. cipher.decrypt("9mx5Zq4JVyjeChTcVjEide4kWCwusFl7P2dSVXtg9IY=");
  71. fail();
  72. } catch (RuntimeException e) {
  73. assertThat(e.getCause()).isInstanceOf(InvalidKeyException.class);
  74. }
  75. }
  76. @Test
  77. public void decrypt_other_key() throws Exception {
  78. URL resource = getClass().getResource("/org/sonar/api/config/internal/AesCipherTest/other_secret_key.txt");
  79. AesCipher cipher = new AesCipher(new File(resource.toURI()).getCanonicalPath());
  80. try {
  81. // text encrypted with another key
  82. cipher.decrypt("9mx5Zq4JVyjeChTcVjEide4kWCwusFl7P2dSVXtg9IY=");
  83. fail();
  84. } catch (RuntimeException e) {
  85. assertThat(e.getCause()).isInstanceOf(BadPaddingException.class);
  86. }
  87. }
  88. @Test
  89. public void encryptThenDecrypt() throws Exception {
  90. AesCipher cipher = new AesCipher(pathToSecretKey());
  91. assertThat(cipher.decrypt(cipher.encrypt("foo"))).isEqualTo("foo");
  92. }
  93. @Test
  94. public void testDefaultPathToSecretKey() {
  95. AesCipher cipher = new AesCipher(null);
  96. String path = cipher.getPathToSecretKey();
  97. assertThat(StringUtils.isNotBlank(path)).isTrue();
  98. assertThat(new File(path).getName()).isEqualTo("sonar-secret.txt");
  99. }
  100. @Test
  101. public void loadSecretKeyFromFile() throws Exception {
  102. AesCipher cipher = new AesCipher(null);
  103. Key secretKey = cipher.loadSecretFileFromFile(pathToSecretKey());
  104. assertThat(secretKey.getAlgorithm()).isEqualTo("AES");
  105. assertThat(secretKey.getEncoded().length).isGreaterThan(10);
  106. }
  107. @Test
  108. public void loadSecretKeyFromFile_trim_content() throws Exception {
  109. URL resource = getClass().getResource("/org/sonar/api/config/internal/AesCipherTest/non_trimmed_secret_key.txt");
  110. String path = new File(resource.toURI()).getCanonicalPath();
  111. AesCipher cipher = new AesCipher(null);
  112. Key secretKey = cipher.loadSecretFileFromFile(path);
  113. assertThat(secretKey.getAlgorithm()).isEqualTo("AES");
  114. assertThat(secretKey.getEncoded().length).isGreaterThan(10);
  115. }
  116. @Test
  117. public void loadSecretKeyFromFile_file_does_not_exist() throws Exception {
  118. thrown.expect(IllegalStateException.class);
  119. AesCipher cipher = new AesCipher(null);
  120. cipher.loadSecretFileFromFile("/file/does/not/exist");
  121. }
  122. @Test
  123. public void loadSecretKeyFromFile_no_property() throws Exception {
  124. thrown.expect(IllegalStateException.class);
  125. AesCipher cipher = new AesCipher(null);
  126. cipher.loadSecretFileFromFile(null);
  127. }
  128. @Test
  129. public void hasSecretKey() throws Exception {
  130. AesCipher cipher = new AesCipher(pathToSecretKey());
  131. assertThat(cipher.hasSecretKey()).isTrue();
  132. }
  133. @Test
  134. public void doesNotHaveSecretKey() {
  135. AesCipher cipher = new AesCipher("/my/twitter/id/is/SimonBrandhof");
  136. assertThat(cipher.hasSecretKey()).isFalse();
  137. }
  138. private String pathToSecretKey() throws Exception {
  139. URL resource = getClass().getResource("/org/sonar/api/config/internal/AesCipherTest/aes_secret_key.txt");
  140. return new File(resource.toURI()).getCanonicalPath();
  141. }
  142. }