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.

CipherUtils.java 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /*
  2. * Copyright (c) 2006-2007 Chris Smith, Shane Mc Cormack, Gregory Holmes
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package uk.org.ownage.dmdirc;
  23. import java.io.IOException;
  24. import java.io.UnsupportedEncodingException;
  25. import java.security.MessageDigest;
  26. import java.security.NoSuchAlgorithmException;
  27. import java.security.spec.AlgorithmParameterSpec;
  28. import java.security.spec.KeySpec;
  29. import javax.crypto.Cipher;
  30. import javax.crypto.IllegalBlockSizeException;
  31. import javax.crypto.SecretKey;
  32. import javax.crypto.SecretKeyFactory;
  33. import javax.crypto.spec.PBEKeySpec;
  34. import javax.crypto.spec.PBEParameterSpec;
  35. import javax.swing.JOptionPane;
  36. import uk.org.ownage.dmdirc.logger.ErrorLevel;
  37. import uk.org.ownage.dmdirc.logger.Logger;
  38. /**
  39. * Helper class to encrypt and decrypt strings, requests passwords if needed.
  40. */
  41. public final class CipherUtils {
  42. /**
  43. * Encryption cipher.
  44. */
  45. private static Cipher ecipher;
  46. /**
  47. * Decryption cipher.
  48. */
  49. private static Cipher dcipher;
  50. /**
  51. * Salt.
  52. */
  53. private static final byte[] SALT = {
  54. (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32,
  55. (byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03,
  56. };
  57. /**
  58. * Iteration count.
  59. */
  60. private static final int ITERATIONS = 19;
  61. /**
  62. * number of auth attemps before failing the attempt.
  63. */
  64. private static final int AUTH_TRIES = 4;
  65. /**
  66. * User password.
  67. */
  68. private static String password;
  69. /**
  70. * Prevents creation of a new instance of Encipher.
  71. */
  72. private CipherUtils() {
  73. }
  74. /**
  75. * Encrypts a string using the stored settings. Will return null if the
  76. * automatic user authentication fails - use checkauth and auth.
  77. * @param str String to encrypt
  78. * @return Encrypted string
  79. */
  80. public static String encrypt(final String str) {
  81. if (!checkAuthed()) {
  82. if (auth()) {
  83. createCiphers();
  84. } else {
  85. return null;
  86. }
  87. }
  88. try {
  89. return new String(ecipher.doFinal(str.getBytes("UTF8")));
  90. } catch (javax.crypto.BadPaddingException e) {
  91. Logger.error(ErrorLevel.WARNING, "Unable to decrypt string", e);
  92. } catch (IllegalBlockSizeException e) {
  93. Logger.error(ErrorLevel.WARNING, "Unable to decrypt string", e);
  94. } catch (UnsupportedEncodingException e) {
  95. Logger.error(ErrorLevel.WARNING, "Unable to decrypt string", e);
  96. } catch (java.io.IOException e) {
  97. Logger.error(ErrorLevel.WARNING, "Unable to decrypt string", e);
  98. }
  99. return null;
  100. }
  101. /**
  102. * Encrypts a string using the stored settings. Will return null if the
  103. * automatic user authentication fails - use checkauth and auth.
  104. * @param str String to decrypt
  105. * @return Decrypted string
  106. */
  107. public static String decrypt(final String str) {
  108. if (!checkAuthed()) {
  109. if (auth()) {
  110. createCiphers();
  111. } else {
  112. return null;
  113. }
  114. }
  115. try {
  116. return new String(dcipher.doFinal(str.getBytes()), "UTF8");
  117. } catch (javax.crypto.BadPaddingException e) {
  118. Logger.error(ErrorLevel.WARNING, "Unable to decrypt string", e);
  119. } catch (IllegalBlockSizeException e) {
  120. Logger.error(ErrorLevel.WARNING, "Unable to decrypt string", e);
  121. } catch (UnsupportedEncodingException e) {
  122. Logger.error(ErrorLevel.WARNING, "Unable to decrypt string", e);
  123. } catch (java.io.IOException e) {
  124. Logger.error(ErrorLevel.WARNING, "Unable to decrypt string", e);
  125. }
  126. return null;
  127. }
  128. /**
  129. * Performs a SHA-512 hash.
  130. * @param data String to hashed
  131. * @return hashed string
  132. */
  133. public static String hash(final String data) {
  134. try {
  135. return new String(MessageDigest.getInstance("SHA-512")
  136. .digest(data.getBytes("UTF8")));
  137. } catch (NoSuchAlgorithmException e) {
  138. Logger.error(ErrorLevel.WARNING, "Unable to hash string", e);
  139. } catch (IOException e) {
  140. Logger.error(ErrorLevel.WARNING, "Unable to hash string", e);
  141. }
  142. return null;
  143. }
  144. /**
  145. * Checks if a user is authed.
  146. *
  147. * @return true if authed, false otherwise
  148. */
  149. public static boolean checkAuthed() {
  150. if (dcipher != null && ecipher != null) {
  151. return true;
  152. }
  153. return false;
  154. }
  155. /**
  156. * creates ciphers.
  157. */
  158. private static void createCiphers() {
  159. try {
  160. final KeySpec keySpec = new PBEKeySpec(
  161. password.toCharArray(), SALT, ITERATIONS);
  162. final SecretKey key = SecretKeyFactory.
  163. getInstance("PBEWithMD5AndDES").generateSecret(keySpec);
  164. ecipher = Cipher.getInstance(key.getAlgorithm());
  165. dcipher = Cipher.getInstance(key.getAlgorithm());
  166. final AlgorithmParameterSpec paramSpec =
  167. new PBEParameterSpec(SALT, ITERATIONS);
  168. ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
  169. dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
  170. } catch (java.security.InvalidAlgorithmParameterException e) {
  171. Logger.error(ErrorLevel.WARNING, "Unable to create ciphers", e);
  172. ecipher = null;
  173. dcipher = null;
  174. } catch (java.security.spec.InvalidKeySpecException e) {
  175. Logger.error(ErrorLevel.WARNING, "Unable to create ciphers", e);
  176. ecipher = null;
  177. dcipher = null;
  178. } catch (javax.crypto.NoSuchPaddingException e) {
  179. Logger.error(ErrorLevel.WARNING, "Unable to create ciphers", e);
  180. ecipher = null;
  181. dcipher = null;
  182. } catch (java.security.NoSuchAlgorithmException e) {
  183. Logger.error(ErrorLevel.WARNING, "Unable to create ciphers", e);
  184. ecipher = null;
  185. dcipher = null;
  186. } catch (java.security.InvalidKeyException e) {
  187. Logger.error(ErrorLevel.WARNING, "Unable to create ciphers", e);
  188. ecipher = null;
  189. dcipher = null;
  190. }
  191. }
  192. /**
  193. * Auths a user and sets the password.
  194. *
  195. * @return true if auth was successful, false otherwise.
  196. */
  197. public static boolean auth() {
  198. String passwordHash = null;
  199. String prompt = "Please enter your password";
  200. int tries = 1;
  201. if (Config.hasOption("encryption", "password")) {
  202. password = Config.getOption("encryption", "password");
  203. } else {
  204. if (Config.hasOption("encryption", "passwordHash")) {
  205. passwordHash = Config.getOption("encryption", "passwordHash");
  206. }
  207. passwordHash = "moo";
  208. while ((password == null || password.length() == 0) && tries < AUTH_TRIES) {
  209. password = JOptionPane.showInputDialog(prompt);
  210. if (passwordHash == null) {
  211. passwordHash = hash(password);
  212. Config.setOption("encryption", "passwordHash", passwordHash);
  213. Config.save();
  214. }
  215. if (!hash(password).equals(passwordHash)) {
  216. prompt = "<html>Password mis-match<br>Please re-enter "
  217. + "your password</html>";
  218. tries++;
  219. password = null;
  220. }
  221. }
  222. }
  223. if (tries == AUTH_TRIES) {
  224. return false;
  225. }
  226. return true;
  227. }
  228. }