PageRenderTime 38ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/org/owasp/esapi/crypto/CipherSpec.cfc

https://github.com/LoicMahieu/cfesapi
ColdFusion CFScript | 342 lines | 245 code | 66 blank | 31 comment | 47 complexity | 4d3f1615e504009acfd95ba1349af81e MD5 | raw file
Possible License(s): BSD-3-Clause, CC-BY-SA-3.0
  1. <!--- /**
  2. * OWASP Enterprise Security API (ESAPI)
  3. *
  4. * This file is part of the Open Web Application Security Project (OWASP)
  5. * Enterprise Security API (ESAPI) project. For details, please see
  6. * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
  7. *
  8. * Copyright (c) 2011 - The OWASP Foundation
  9. *
  10. * The ESAPI is published by OWASP under the BSD license. You should read and accept the
  11. * LICENSE before you use, modify, and/or redistribute this software.
  12. *
  13. * @author Damon Miller
  14. * @created 2011
  15. */ --->
  16. <cfcomponent displayname="CipherSpec" extends="cfesapi.org.owasp.esapi.lang.Object" output="false" hint="Specifies all the relevant configuration data needed in constructing and using a {@link javax.crypto.Cipher} except for the encryption key. The 'setters' all return a reference to {@code this} so that they can be strung together. Note: While this is a useful class in it's own right, it should primarily be regarded as an implementation class to use with ESAPI encryption, especially the reference implementation. It is not intended to be used directly by application developers, but rather only by those either extending ESAPI or in the ESAPI reference implementation. Use directly by application code is not recommended or supported.">
  17. <cfscript>
  18. instance.serialVersionUID = 20090822;// version, in YYYYMMDD format
  19. instance.ESAPI = "";
  20. this.cipher_xform_ = "";
  21. this.keySize_ = "";// In bits
  22. this.blockSize_ = 16;// In bytes! I.e., 128 bits!!!
  23. this.iv_ = toBinary("");
  24. // Cipher transformation component. Format is ALG/MODE/PADDING
  25. CipherTransformationComponent = {ALG=newComponent("cfesapi.org.owasp.esapi.crypto.CipherTransformationComponent").init("ALG", 1), MODE=newComponent("cfesapi.org.owasp.esapi.crypto.CipherTransformationComponent").init("MODE", 2), PADDING=newComponent("cfesapi.org.owasp.esapi.crypto.CipherTransformationComponent").init("PADDING", 3)};
  26. </cfscript>
  27. <cffunction access="public" returntype="CipherSpec" name="init" output="false"
  28. hint="CTOR that explicitly sets everything.">
  29. <cfargument required="true" type="cfesapi.org.owasp.esapi.ESAPI" name="ESAPI"/>
  30. <cfargument name="cipher"/>
  31. <cfargument type="String" name="cipherXform" hint="The cipher transformation"/>
  32. <cfargument type="numeric" name="keySize" hint="The key size (in bits)."/>
  33. <cfargument type="numeric" name="blockSize" hint="The block size (in bytes)."/>
  34. <cfargument type="binary" name="iv" hint="The initialization vector. Null if not applicable."/>
  35. <cfset var local = {}/>
  36. <cfscript>
  37. instance.ESAPI = arguments.ESAPI;
  38. CryptoHelper = newComponent("cfesapi.org.owasp.esapi.crypto.CryptoHelper").init(instance.ESAPI);
  39. if(structKeyExists(arguments, "cipher")) {
  40. setCipherTransformation(arguments.cipher.getAlgorithm(), true);
  41. setBlockSize(arguments.cipher.getBlockSize());
  42. local.iv = arguments.cipher.getIV();
  43. if(structKeyExists(local, "iv")) {
  44. setIV(arguments.cipher.getIV());
  45. }
  46. }
  47. else {
  48. if(structKeyExists(arguments, "cipherXform")) {
  49. setCipherTransformation(arguments.cipherXform);
  50. }
  51. else {
  52. setCipherTransformation(instance.ESAPI.securityConfiguration().getCipherTransformation());
  53. }
  54. if(structKeyExists(arguments, "blockSize")) {
  55. setBlockSize(arguments.blockSize);
  56. }
  57. if(structKeyExists(arguments, "iv")) {
  58. setIV(arguments.iv);
  59. }
  60. }
  61. if(structKeyExists(arguments, "keySize")) {
  62. setKeySize(arguments.keySize);
  63. }
  64. else {
  65. setKeySize(instance.ESAPI.securityConfiguration().getEncryptionKeyLength());
  66. }
  67. return this;
  68. </cfscript>
  69. </cffunction>
  70. <cffunction access="public" returntype="CipherSpec" name="setCipherTransformation" output="false"
  71. hint="Set the cipher transformation for this {@code CipherSpec}. This is only used by the CTOR {@code CipherSpec(Cipher)} and {@code CipherSpec(Cipher, int)}.">
  72. <cfargument required="true" type="String" name="cipherXform" hint="The cipher transformation string; e.g., 'DESede/CBC/PKCS5Padding'. May not be null or empty."/>
  73. <cfargument type="boolean" name="fromCipher" default="false" hint="If true, the cipher transformation was set via {@code Cipher.getAlgorithm()} which may only return the actual algorithm. In that case we check and if all 3 parts were not specified, then we specify the parts that were based on 'ECB' as the default cipher mode and 'NoPadding' as the default padding scheme."/>
  74. <cfset var local = {}/>
  75. <cfscript>
  76. if(!newJava("org.owasp.esapi.StringUtilities").notNullOrEmpty(arguments.cipherXform, true)) {// Yes, really want '!' here.
  77. throwError(newJava("java.lang.IllegalArgumentException").init("Cipher transformation may not be null or empty string (after trimming whitespace)."));
  78. }
  79. local.parts = arrayLen(arguments.cipherXform.split("/"));
  80. assert(iif(!arguments.fromCipher, de(local.parts == 3), de(true)), "Malformed cipherXform (" & arguments.cipherXform & '); must have form: "alg/mode/paddingscheme"');
  81. if(arguments.fromCipher && (local.parts != 3)) {
  82. // Indicates cipherXform was set based on Cipher.getAlgorithm()
  83. // and thus may not be a *complete* cipher transformation.
  84. if(local.parts == 1) {
  85. // Only algorithm was given.
  86. arguments.cipherXform &= "/ECB/NoPadding";
  87. }
  88. else if(local.parts == 2) {
  89. // Only algorithm and mode was given.
  90. arguments.cipherXform &= "/NoPadding";
  91. }
  92. else if(local.parts == 3) {
  93. // All three parts provided. Do nothing. Could happen if not compiled with
  94. // assertions enabled.// Do nothing - shown only for completeness.
  95. }
  96. else {
  97. // Should never happen unless Cipher implementation is totally screwed up.
  98. throwError(newJava("java.lang.IllegalArgumentException").init('Cipher transformation "' & arguments.cipherXform & '" must have form "alg/mode/paddingscheme"'));
  99. }
  100. }
  101. else if(!arguments.fromCipher && local.parts != 3) {
  102. throwError(newJava("java.lang.IllegalArgumentException").init("Malformed cipherXform (" & arguments.cipherXform & '); must have form: "alg/mode/paddingscheme"'));
  103. }
  104. assert(arrayLen(arguments.cipherXform.split("/")) == 3, "Implementation error setCipherTransformation()");
  105. this.cipher_xform_ = arguments.cipherXform;
  106. return this;
  107. </cfscript>
  108. </cffunction>
  109. <cffunction access="public" returntype="String" name="getCipherTransformation" output="false"
  110. hint="Get the cipher transformation.">
  111. <cfscript>
  112. return this.cipher_xform_;
  113. </cfscript>
  114. </cffunction>
  115. <cffunction access="public" returntype="CipherSpec" name="setKeySize" output="false"
  116. hint="Set the key size for this {@code CipherSpec}.">
  117. <cfargument required="true" type="numeric" name="keySize" hint="The key size, in bits. Must be positive integer."/>
  118. <cfscript>
  119. assert(keySize > 0, "keySize must be > 0; keySize=" & keySize);
  120. this.keySize_ = arguments.keySize;
  121. return this;
  122. </cfscript>
  123. </cffunction>
  124. <cffunction access="public" returntype="numeric" name="getKeySize" output="false"
  125. hint="Retrieve the key size, in bits.">
  126. <cfscript>
  127. return this.keySize_;
  128. </cfscript>
  129. </cffunction>
  130. <cffunction access="public" returntype="CipherSpec" name="setBlockSize" output="false"
  131. hint="Set the block size for this {@code CipherSpec}.">
  132. <cfargument required="true" type="numeric" name="blockSize" hint="The block size, in bytes. Must be positive integer."/>
  133. <cfscript>
  134. assert(blockSize > 0, "blockSize must be > 0; blockSize=" & blockSize);
  135. this.blockSize_ = arguments.blockSize;
  136. return this;
  137. </cfscript>
  138. </cffunction>
  139. <cffunction access="public" returntype="numeric" name="getBlockSize" output="false"
  140. hint="Retrieve the block size, in bytes.">
  141. <cfscript>
  142. return this.blockSize_;
  143. </cfscript>
  144. </cffunction>
  145. <cffunction access="public" returntype="String" name="getCipherAlgorithm" output="false"
  146. hint="Retrieve the cipher algorithm.">
  147. <cfscript>
  148. return getFromCipherXform(CipherTransformationComponent.ALG);
  149. </cfscript>
  150. </cffunction>
  151. <cffunction access="public" returntype="String" name="getCipherMode" output="false"
  152. hint="Retrieve the cipher mode.">
  153. <cfscript>
  154. return getFromCipherXform(CipherTransformationComponent.MODE);
  155. </cfscript>
  156. </cffunction>
  157. <cffunction access="public" returntype="String" name="getPaddingScheme" output="false"
  158. hint="Retrieve the cipher padding scheme.">
  159. <cfscript>
  160. return getFromCipherXform(CipherTransformationComponent.PADDING);
  161. </cfscript>
  162. </cffunction>
  163. <cffunction access="public" returntype="binary" name="getIV" output="false"
  164. hint="Retrieve the initialization vector (IV).">
  165. <cfscript>
  166. return this.iv_;
  167. </cfscript>
  168. </cffunction>
  169. <cffunction access="public" returntype="CipherSpec" name="setIV" output="false"
  170. hint="Set the initialization vector (IV).">
  171. <cfargument required="true" type="binary" name="iv" hint="The byte array to set as the IV. A copy of the IV is saved. This parameter is ignored if the cipher mode does not require an IV."/>
  172. <cfscript>
  173. assert(requiresIV() && (structKeyExists(arguments, "iv") && arrayLen(arguments.iv) != 0), "Required IV cannot be null or 0 length");
  174. // Don't store a reference, but make a copy!
  175. if(structKeyExists(arguments, "iv")) {// Allow null IV for ECB mode.
  176. this.iv_ = newByte(arrayLen(arguments.iv));
  177. CryptoHelper.copyByteArray(arguments.iv, this.iv_);
  178. }
  179. return this;
  180. </cfscript>
  181. </cffunction>
  182. <cffunction access="public" returntype="boolean" name="requiresIV" output="false"
  183. hint="Return true if the cipher mode requires an IV.">
  184. <cfset var local = {}/>
  185. <cfscript>
  186. local.cm = getCipherMode();
  187. // Add any other cipher modes supported by JCE but not requiring IV.
  188. // ECB is the only one I'm aware of that doesn't. Mode is not case
  189. // sensitive.
  190. if("ECB" == local.cm) {
  191. return false;
  192. }
  193. return true;
  194. </cfscript>
  195. </cffunction>
  196. <cffunction access="public" returntype="String" name="toStringESAPI" output="false"
  197. hint="Override {@code Object.toString()} to provide something more useful.">
  198. <cfset var local = {}/>
  199. <cfscript>
  200. local.sb = newComponent("cfesapi.org.owasp.esapi.lang.StringBuilder").init("CipherSpec: ");
  201. local.sb.append(getCipherTransformation()).append("; keysize= ").append(javaCast("int", getKeySize()));
  202. local.sb.append(" bits; blocksize= ").append(javaCast("int", getBlockSize())).append(" bytes");
  203. local.iv = getIV();
  204. local.ivLen = "";
  205. if(structKeyExists(local, "iv")) {
  206. local.ivLen = "" & arrayLen(local.iv);// Convert length to a string
  207. }
  208. else {
  209. local.ivLen = "[No IV present (not set or not required)]";
  210. }
  211. local.sb.append("; IV length = ").append(local.ivLen).append(" bytes.");
  212. return local.sb.toStringESAPI();
  213. </cfscript>
  214. </cffunction>
  215. <cffunction access="public" returntype="boolean" name="equalsESAPI" output="false">
  216. <cfargument required="true" name="other"/>
  217. <cfset var local = {}/>
  218. <cfscript>
  219. local.result = false;
  220. /* throws error - anyway to make this work?
  221. if(this == other) {
  222. return true;
  223. } */
  224. if(!isObject(arguments.other)) {
  225. return false;
  226. }
  227. if(isInstanceOf(arguments.other, "cfesapi.org.owasp.esapi.crypto.CipherSpec")) {
  228. NullSafe = newJava("org.owasp.esapi.util.NullSafe");
  229. local.that = arguments.other;
  230. local.result = (local.that.canEqual(this) && NullSafe.equals(this.cipher_xform_, local.that.cipher_xform_) && this.keySize_ == local.that.keySize_ && this.blockSize_ == local.that.blockSize_ && CryptoHelper.arrayCompare(this.iv_, local.that.iv_));// Comparison safe from timing attacks.
  231. }
  232. return local.result;
  233. </cfscript>
  234. </cffunction>
  235. <cffunction access="public" returntype="int" name="hashCodeESAPI" output="false">
  236. <cfset var local = {}/>
  237. <cfscript>
  238. local.sb = newComponent("cfesapi.org.owasp.esapi.lang.StringBuilder").init();
  239. local.sb.append(getCipherTransformation());
  240. local.sb.append("" & getKeySize());
  241. local.sb.append("" & getBlockSize());
  242. local.iv = getIV();
  243. if(structKeyExists(local, "iv") && local.iv.length > 0) {
  244. local.ivStr = "";
  245. try {
  246. local.ivStr = newJava("java.lang.String").init(local.iv, "UTF-8");
  247. }
  248. catch(java.io.UnsupportedEncodingException ex) {
  249. // Should never happen as UTF-8 encode supported by rt.jar,
  250. // but it it does, just use default encoding.
  251. local.ivStr = newJava("java.lang.String").init(local.iv);
  252. }
  253. local.sb.append(local.ivStr);
  254. }
  255. return local.sb.toStringESAPI().hashCode();
  256. </cfscript>
  257. </cffunction>
  258. <cffunction access="package" returntype="boolean" name="canEqual" output="false"
  259. hint="Needed for correct definition of equals for general classes. (Technically not needed for 'final' classes like this class though; this will just allow it to work in the future should we decide to allow sub-classing of this class.) See {@link http://www.artima.com/lejava/articles/equality.html} for full explanation.">
  260. <cfargument required="true" name="other"/>
  261. <cfscript>
  262. return isInstanceOf(arguments.other, "cfesapi.org.owasp.esapi.crypto.CipherSpec");
  263. </cfscript>
  264. </cffunction>
  265. <cffunction access="private" returntype="String" name="getFromCipherXform" output="false"
  266. hint="Split the current cipher transformation and return the requested part. ">
  267. <cfargument required="true" type="cfesapi.org.owasp.esapi.crypto.CipherTransformationComponent" name="obj" hint="The component of the cipher transformation to return."/>
  268. <cfset var local = {}/>
  269. <cfscript>
  270. local.part = arguments.obj.ordinal();
  271. local.parts = getCipherTransformation().split("/");
  272. assert(arrayLen(local.parts) == 3, "Invalid cipher transformation: " & getCipherTransformation());
  273. return local.parts[local.part];
  274. </cfscript>
  275. </cffunction>
  276. </cfcomponent>