PageRenderTime 53ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

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

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