PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/org/owasp/esapi/reference/crypto/ReferenceEncryptedProperties.java

http://owasp-esapi-java.googlecode.com/
Java | 293 lines | 149 code | 36 blank | 108 comment | 17 complexity | f632ff80a5faf024100beded7734bebe 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) 2007 - 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 Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
  14. * @created 2007
  15. */
  16. package org.owasp.esapi.reference.crypto;
  17. import java.io.BufferedReader;
  18. import java.io.ByteArrayInputStream;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.io.PrintStream;
  22. import java.io.PrintWriter;
  23. import java.io.Reader;
  24. import java.util.Collection;
  25. import java.util.Enumeration;
  26. import java.util.Properties;
  27. import java.util.Set;
  28. import org.owasp.esapi.ESAPI;
  29. import org.owasp.esapi.EncryptedProperties;
  30. import org.owasp.esapi.Logger;
  31. import org.owasp.esapi.crypto.CipherText;
  32. import org.owasp.esapi.crypto.PlainText;
  33. import org.owasp.esapi.errors.EncryptionRuntimeException;
  34. /**
  35. * Reference implementation of the {@code EncryptedProperties} interface. This
  36. * implementation wraps a normal properties file, and creates surrogates for the
  37. * {@code getProperty} and {@code setProperty} methods that perform encryption
  38. * and decryption based on {@code Encryptor}.
  39. * <p>
  40. * This implementation differs from {@code DefaultEncryptedProperties} in that
  41. * it actually extends from {@code java.util.Properties} for applications that need an
  42. * instance of that class. In order to do so, the {@code getProperty} and
  43. * {@code setProperty} methods were modified to throw {@code EncryptionRuntimeException}
  44. * instead of {@code EncryptionException}.
  45. *
  46. * @author August Detlefsen (augustd at codemagi dot com)
  47. * <a href="http://www.codemagi.com">CodeMagi, Inc.</a>
  48. * @author kevin.w.wall@gmail.com
  49. * @since October 8, 2010
  50. * @see org.owasp.esapi.EncryptedProperties
  51. * @see org.owasp.esapi.reference.crypto.DefaultEncryptedProperties
  52. */
  53. public class ReferenceEncryptedProperties extends java.util.Properties implements EncryptedProperties {
  54. /**
  55. * serverVersionUID; use format of YYYYMMDD.
  56. */
  57. private static final long serialVersionUID = 20120718L;
  58. /** The logger. */
  59. private final Logger logger = ESAPI.getLogger(this.getClass());
  60. private static final String[] GET_ERROR_MESSAGES = new String[]{
  61. ": failed decoding from base64",
  62. ": failed to deserialize properly",
  63. ": failed to decrypt properly"
  64. };
  65. private static final String[] SET_ERROR_MESSAGES = new String[]{
  66. ": failed to encrypt properly",
  67. ": failed to serialize correctly",
  68. ": failed to base64-encode properly",
  69. ": failed to set base64-encoded value as property. Illegal key name?"
  70. };
  71. /**
  72. * Instantiates a new encrypted properties.
  73. */
  74. public ReferenceEncryptedProperties() {
  75. super();
  76. }
  77. public ReferenceEncryptedProperties(Properties defaults) {
  78. super();
  79. for (Object oKey : defaults.keySet()) {
  80. String key = (oKey instanceof String) ? (String)oKey : oKey.toString();
  81. String value = defaults.getProperty(key);
  82. this.setProperty(key, value);
  83. }
  84. }
  85. /**
  86. * {@inheritDoc}
  87. *
  88. * @throws EncryptionRuntimeException Thrown if decryption fails.
  89. */
  90. @Override
  91. public synchronized String getProperty(String key) throws EncryptionRuntimeException {
  92. int progressMark = 0;
  93. try {
  94. String encryptedValue = super.getProperty(key);
  95. if(encryptedValue==null)
  96. return null;
  97. progressMark = 0;
  98. byte[] serializedCiphertext = ESAPI.encoder().decodeFromBase64(encryptedValue);
  99. progressMark++;
  100. CipherText restoredCipherText = CipherText.fromPortableSerializedBytes(serializedCiphertext);
  101. progressMark++;
  102. PlainText plaintext = ESAPI.encryptor().decrypt(restoredCipherText);
  103. return plaintext.toString();
  104. } catch (Exception e) {
  105. throw new EncryptionRuntimeException("Property retrieval failure",
  106. "Couldn't retrieve encrypted property for property " + key +
  107. GET_ERROR_MESSAGES[progressMark], e);
  108. }
  109. }
  110. /**
  111. * {@inheritDoc}
  112. *
  113. * @throws EncryptionRuntimeException Thrown if decryption fails.
  114. */
  115. @Override
  116. public String getProperty(String key, String defaultValue) throws EncryptionRuntimeException {
  117. String value = getProperty(key);
  118. if (value == null) return defaultValue;
  119. return value;
  120. }
  121. /**
  122. * {@inheritDoc}
  123. *
  124. * @throws EncryptionRuntimeException Thrown if encryption fails.
  125. */
  126. @Override
  127. public synchronized String setProperty(String key, String value) throws EncryptionRuntimeException {
  128. int progressMark = 0;
  129. try {
  130. if ( key == null ) {
  131. throw new NullPointerException("Property name may not be null.");
  132. }
  133. if ( value == null ) {
  134. throw new NullPointerException("Property value may not be null.");
  135. }
  136. // NOTE: Not backward compatible w/ ESAPI 1.4.
  137. PlainText pt = new PlainText(value);
  138. CipherText ct = ESAPI.encryptor().encrypt(pt);
  139. progressMark++;
  140. byte[] serializedCiphertext = ct.asPortableSerializedByteArray();
  141. progressMark++;
  142. String b64str = ESAPI.encoder().encodeForBase64(serializedCiphertext, false);
  143. progressMark++;
  144. return (String)super.put(key, b64str);
  145. } catch (Exception e) {
  146. throw new EncryptionRuntimeException("Property setting failure",
  147. "Couldn't set encrypted property " + key +
  148. SET_ERROR_MESSAGES[progressMark], e);
  149. }
  150. }
  151. /**
  152. * {@inheritDoc}
  153. * @throws IOException Thrown if input stream invalid or does not
  154. * correspond to Java properties file format.
  155. */
  156. @Override
  157. public void load(InputStream in) throws IOException {
  158. super.load(in);
  159. logger.trace(Logger.SECURITY_SUCCESS, "Encrypted properties loaded successfully");
  160. }
  161. /**
  162. * {@inheritDoc}
  163. *
  164. * For JDK 1.5 compatibility, this method has been overridden convert the Reader
  165. * into an InputStream and call the superclass constructor.
  166. *
  167. * @throws IOException Thrown if {@code Reader} input stream invalid or does not
  168. * correspond to Java properties file format.
  169. */
  170. public void load(Reader in) throws IOException {
  171. if (in == null) return;
  172. //read from the reader into a StringBuffer
  173. char[] cbuf = new char[65536];
  174. BufferedReader buff = new BufferedReader(in);
  175. StringBuilder contents = new StringBuilder();
  176. int read_this_time = 0;
  177. while (read_this_time != -1) {
  178. read_this_time = buff.read(cbuf, 0, 65536);
  179. if (read_this_time > 0) contents.append(cbuf, 0, read_this_time);
  180. }
  181. //create a new InputStream from the StringBuffer
  182. InputStream is = new ByteArrayInputStream(contents.toString().getBytes());
  183. super.load(is);
  184. logger.trace(Logger.SECURITY_SUCCESS, "Encrypted properties loaded successfully");
  185. }
  186. /**
  187. * This method has been overridden to throw an {@code UnsupportedOperationException}
  188. */
  189. @Override
  190. public void list(PrintStream out) {
  191. throw new UnsupportedOperationException("This method has been removed for security.");
  192. }
  193. /**
  194. * This method has been overridden to throw an {@code UnsupportedOperationException}
  195. */
  196. @Override
  197. public void list(PrintWriter out) {
  198. throw new UnsupportedOperationException("This method has been removed for security.");
  199. }
  200. /**
  201. * This method has been overridden to throw an {@code UnsupportedOperationException}
  202. */
  203. @SuppressWarnings({ "unchecked", "rawtypes" })
  204. @Override
  205. public Collection values() {
  206. throw new UnsupportedOperationException("This method has been removed for security.");
  207. }
  208. /**
  209. * This method has been overridden to throw an {@code UnsupportedOperationException}
  210. */
  211. @SuppressWarnings({ "unchecked", "rawtypes" })
  212. @Override
  213. public Set entrySet() {
  214. throw new UnsupportedOperationException("This method has been removed for security.");
  215. }
  216. /**
  217. * This method has been overridden to throw an {@code UnsupportedOperationException}
  218. */
  219. @SuppressWarnings({ "unchecked", "rawtypes" })
  220. @Override
  221. public Enumeration elements() {
  222. throw new UnsupportedOperationException("This method has been removed for security.");
  223. }
  224. /**
  225. * This method has been overridden to only accept Strings for key and value, and to encrypt
  226. * those Strings before storing them. Outside classes should always use {@code setProperty}
  227. * to add values to the Properties map. If an outside class does erroneously call this method
  228. * with non-String parameters an {@code IllegalArgumentException} will be thrown.
  229. *
  230. * @param key A String key to add
  231. * @param value A String value to add
  232. * @return The old value associated with the specified key, or {@code null}
  233. * if the key did not exist.
  234. */
  235. @Override
  236. public synchronized Object put(Object key, Object value) {
  237. //if java.util.Properties is calling this method, just forward to the implementation in
  238. //the superclass (java.util.Hashtable)
  239. Throwable t = new Throwable();
  240. for (StackTraceElement trace : t.getStackTrace()) {
  241. if ("java.util.Properties".equals(trace.getClassName()) ) return super.put(key, value);
  242. }
  243. //otherwise, if both arguments are Strings, encrypt and store them
  244. if (key instanceof String && value instanceof String) return setProperty((String)key, (String)value);
  245. //other Object types are not allowed
  246. throw new IllegalArgumentException("This method has been overridden to only accept Strings for key and value.");
  247. }
  248. /**
  249. * This method has been overridden to not print out the keys and values stored in this properties file.
  250. *
  251. * @return The minimal String representation of this class, as per java.lang.Object.
  252. */
  253. @Override
  254. public String toString() {
  255. return getClass().getName() + "@" + Integer.toHexString(hashCode());
  256. }
  257. }