PageRenderTime 57ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/Frameworks/Core/ERExtensions/Sources/er/extensions/crypting/ERXAbstractBlowfishCrypter.java

https://github.com/amagavi/wonder
Java | 222 lines | 128 code | 21 blank | 73 comment | 26 complexity | 0c217d4f619230fb13fc082dd91437a6 MD5 | raw file
  1. package er.extensions.crypting;
  2. import java.io.ByteArrayOutputStream;
  3. import java.security.Key;
  4. import javax.crypto.Cipher;
  5. import com.webobjects.foundation.NSForwardException;
  6. import er.extensions.foundation.ERXStringUtilities;
  7. /**
  8. * ERXAbstractBlowfishCrypter is a blowfish implementation of the crypter
  9. * interface that allows subclasses to override the source of the blowfish key.
  10. * The blowfish cipher is a two-way cipher meaning the original string that was
  11. * encrypted can be retrieved. The way that this version of the blowfish cipher
  12. * is encrypted it is safe to use as a form value.
  13. *
  14. * @author mschrag
  15. */
  16. public abstract class ERXAbstractBlowfishCrypter implements ERXCrypterInterface {
  17. /** Block size of blowfish encrypted strings */
  18. private int _blockSize;
  19. /** Used to cache the blowfish encryption cipher */
  20. private Cipher _encryptCipher;
  21. /** Used to cache the blowfish decryption cipher */
  22. private Cipher _decryptCipher;
  23. public ERXAbstractBlowfishCrypter() {
  24. _blockSize = 8;
  25. }
  26. /**
  27. * Sets the block size to use for this cipher.
  28. *
  29. * @param blockSize
  30. * the block size to use for this cipher
  31. */
  32. public void setBlockSize(int blockSize) {
  33. _blockSize = blockSize;
  34. }
  35. /**
  36. * Returns the block size for this cipher.
  37. *
  38. * @return the block size for this cipher
  39. */
  40. public int blockSize() {
  41. return _blockSize;
  42. }
  43. /**
  44. * Returns the secret key to use for this cipher.
  45. *
  46. * @return a secret key for the blowfish cipher
  47. */
  48. protected abstract Key secretBlowfishKey() throws Exception;
  49. /**
  50. * Creates a blowfish cipher for a given mode. The two possible modes for a
  51. * blowfish cipher are: ENCRYPT and DECRYPT.
  52. *
  53. * @param mode
  54. * of the cipher (encrypting or decrypting)
  55. * @return a blowfish cipher initialized with the given mode and with the
  56. * <code>secretKey</code> from the above method.
  57. */
  58. protected Cipher createBlowfishCipher(int mode) {
  59. try {
  60. Cipher cipher = Cipher.getInstance("Blowfish/ECB/NoPadding");
  61. cipher.init(mode, secretBlowfishKey());
  62. return cipher;
  63. }
  64. catch (java.security.NoSuchAlgorithmException ex) {
  65. throw new NSForwardException(ex, "Couldn't find the Blowfish algorithm; perhaps you do not have the SunJCE security provider installed properly?");
  66. }
  67. catch (Exception e) {
  68. throw new NSForwardException(e);
  69. }
  70. }
  71. /**
  72. * Method used to return the shared instance of the blowfish encryption
  73. * cipher.
  74. *
  75. * @return blowfish encryption cipher
  76. */
  77. protected Cipher encryptCipher() {
  78. if (_encryptCipher == null) {
  79. _encryptCipher = createBlowfishCipher(Cipher.ENCRYPT_MODE);
  80. }
  81. return _encryptCipher;
  82. }
  83. /**
  84. * Method used to return the shared instance of the blowfish decryption
  85. * cipher.
  86. *
  87. * @return blowfish decryption cipher
  88. */
  89. protected Cipher decryptCipher() {
  90. if (_decryptCipher == null) {
  91. _decryptCipher = createBlowfishCipher(Cipher.DECRYPT_MODE);
  92. }
  93. return _decryptCipher;
  94. }
  95. /**
  96. * Decodes a blowfish encoded string. Note that the originally encoded
  97. * string should have been encoded with the same secret key as is used for
  98. * the decoding cipher or else you are going to get garbage. To encode a
  99. * string have a look at <code>blowfishEncode</code>.
  100. *
  101. * @param cryptedText
  102. * blowfish encoded string to be decoded
  103. * @return decode clear text string
  104. */
  105. public String decrypt(String cryptedText) {
  106. if (cryptedText == null) {
  107. return null;
  108. }
  109. int length = cryptedText.length();
  110. if (length % 16 != 0) {
  111. return null;
  112. }
  113. ByteArrayOutputStream result = new ByteArrayOutputStream();
  114. byte[] clearText = null;
  115. byte[] encryptedBytes = new byte[_blockSize];
  116. int i = 0;
  117. for (int j = 0; j < length;) {
  118. char c1 = cryptedText.charAt(j++);
  119. int b1 = c1 < 'a' ? c1 - '0' : c1 - 'a' + 10;
  120. char c2 = cryptedText.charAt(j++);
  121. int b2 = c2 < 'a' ? c2 - '0' : c2 - 'a' + 10;
  122. encryptedBytes[i++] = (byte) ((b1 << 4) + b2);
  123. if (i == _blockSize) {
  124. // we filled a block
  125. try {
  126. clearText = decryptCipher().doFinal(encryptedBytes);
  127. }
  128. catch (Exception e) {
  129. throw new NSForwardException(e);
  130. }
  131. for (int k = 0; k < _blockSize; k++) {
  132. if (clearText[k] != 0) {
  133. result.write(clearText[k]);
  134. }
  135. }
  136. i = 0;
  137. }
  138. }
  139. if (i != 0) {
  140. for (int j = i; j < _blockSize; j++) {
  141. encryptedBytes[j] = 0;
  142. }
  143. try {
  144. clearText = decryptCipher().doFinal(encryptedBytes);
  145. }
  146. catch (Exception e) {
  147. throw new NSForwardException(e);
  148. }
  149. for (int k = 0; k < _blockSize; k++) {
  150. result.write(clearText[k]);
  151. }
  152. }
  153. return ERXStringUtilities.fromUTF8Bytes(result.toByteArray());
  154. }
  155. /**
  156. * Blowfish encodes a given string using the secret key specified in the
  157. * System property: <b>ERBlowfishCipherKey</b>. The blowfish cipher is a
  158. * two way cipher meaning that given the secret key you can de-cipher what
  159. * the original string is. For one-way encryption look at methods dealing
  160. * with the Sha alogrithm. To decode a blowfish encoded string use the
  161. * method: <code>blowfishDecode</code>. The resultant string from
  162. * encoding a string is safe for use in urls and cookies.
  163. *
  164. * @param clearText
  165. * string to be encrypted
  166. * @return encrypted string
  167. */
  168. public String encrypt(String clearText) {
  169. if (clearText == null) {
  170. return null;
  171. }
  172. byte clearTextBytes[] = ERXStringUtilities.toUTF8Bytes(clearText);
  173. StringBuilder result = new StringBuilder();
  174. int pos = 0, length = clearTextBytes.length;
  175. byte[] bytesToEncrypt = new byte[_blockSize];
  176. byte[] encryptedBytes = null;
  177. while (pos < length) {
  178. int k = 0;
  179. for (int j = pos; j < length && j < pos + _blockSize; k++, j++) {
  180. bytesToEncrypt[k] = clearTextBytes[j];
  181. }
  182. if (k < _blockSize) {
  183. for (int l = k; l < _blockSize; l++) {
  184. bytesToEncrypt[l] = 0;
  185. }
  186. }
  187. try {
  188. encryptedBytes = encryptCipher().doFinal(bytesToEncrypt);
  189. }
  190. catch (Exception e) {
  191. throw new NSForwardException(e);
  192. }
  193. for (k = 0; k < _blockSize; k++) {
  194. result.append(ERXStringUtilities.HEX_CHARS[(encryptedBytes[k] >>> 4) & 0xf]);
  195. result.append(ERXStringUtilities.HEX_CHARS[encryptedBytes[k] & 0xf]);
  196. }
  197. pos += _blockSize;
  198. }
  199. return result.toString();
  200. }
  201. }