All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.emory.mathcs.util.security.CharStrings Maven / Gradle / Ivy

/*
 * Written by Dawid Kurzyniec and released to the public domain, as explained
 * at http://creativecommons.org/licenses/publicdomain
 */

package edu.emory.mathcs.util.security;

import java.util.*;
import java.io.*;

/**
 * Utility methods to securely manipulate on character arrays. The methods
 * allow to treat the character arrays similarly to strings, yet they ensure
 * that all temporary arrays are zeroed-out before discarding.
 * 

* Application of this class stems from the fact that String class is not * appropriate for holding passwords and other sensitive information. * Strings cannot be zeroed-out before unreferencing, thus the content * may be dangling in memory for quite a while before it is garbage-collected, * and it can stay in the process data block even longer, until it is * overwritten. It has been demonstrated that attacker can obtain the data * in clear text by forcing the operating system to swap out the application * in question, and then by reading the swap file. * To minimize the risk, sensitive data should be cleared explicitly as soon as * possible. It suggests using mutable character arrays in favor of strings. * This class allows to operate on such arrays much like on strings, in * particular, it provides methods to securely concatenate them, as well as * write them to, and read them from streams in the UTF format. * * @author Dawid Kurzyniec * @version 1.0 */ public class CharStrings { /** this is an utility class */ private CharStrings() {} /** * Returns a concatenation of two character arrays. * @param s1 first array * @param s2 second array * @return new array containing s1 concatenated with s2 */ public static char[] concat(char[] s1, char[] s2) { if (s1 == null) return s2; if (s2 == null) return s1; char[] s3 = new char[s1.length + s2.length]; System.arraycopy(s1, 0, s3, 0, s1.length); System.arraycopy(s2, 0, s3, s1.length, s2.length); return s3; } /** * Compares two character arrays. * * @param s1 first array * @param s2 second array * @return true if arrays have identical content; false otherwise */ public static boolean equals(char[] s1, char[] s2) { return Arrays.equals(s1, s2); } /** * Zeroes-out the specified character array. * @param s the array to zero-out */ public static void clear(char[] s) { if (s != null) Arrays.fill(s, (char)0); } /** * Writes the specified character array to the output stream using UTF-8 * encoding. * * @param out the output to write to * @param s array to write to * @return the number of bytes written * @throws IOException if I/O error occurs */ public static int writeUTF(OutputStream out, char[] s) throws IOException { return writeUTF(out, s, 0, s.length); } /** * Writes a portion of the specified character array to the output stream * using UTF-8 encoding. * * @param out the output to write to * @param s array to write to * @param off start offset within s * @param len number of characters to write * @return the number of bytes written * @throws IOException if I/O error occurs */ public static int writeUTF(OutputStream out, char[] s, int off, int len) throws IOException { int utflen = getUTFLen(s, off, len); if (utflen > 65535) { throw new UTFDataFormatException(); } byte[] dest = new byte[utflen+2]; dest[0] = (byte) ((utflen >>> 8) & 0xFF); dest[1] = (byte) ((utflen >>> 0) & 0xFF); toUTF(s, off, len, dest, 2); out.write(dest); Arrays.fill(dest, (byte)0); return dest.length; } /** * Converts the specified character array into its UTF-8 encoding. * * @param s the array to encode * @return UTF-8 encoded array */ public static byte[] toUTF(char[] s) { return toUTF(s, 0, s.length); } /** * Converts a portion of the specified character array into its UTF-8 * encoding. * * @param s the array to encode * @param off the start offset within s * @param len the number of characters to encode * @return UTF-8 encoded array */ public static byte[] toUTF(char[] s, int off, int len) { byte[] dest = new byte[getUTFLen(s, off, len)]; toUTF(s, off, len, dest, 0); return dest; } /** * Returns the number of bytes of an UTF-8 encoding of a portion of the * specified character array. * * @param s the character array * @param off the start offset within s * @param len the number of characters to include * @return the number of bytes of an UTF-8 encoding */ public static int getUTFLen(char[] s, int off, int len) { if (s == null) { throw new NullPointerException(); } else if ((off < 0) || (off > s.length) || (len < 0) || ((off + len) > s.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } int utflen = 0; int c; for (int i = 0; i < len; i++) { c = s[i]; if ((c >= 0x0001) && (c <= 0x007F)) { utflen++; } else if (c > 0x07FF) { utflen += 3; } else { utflen += 2; } } return utflen; } private static void toUTF(char[] s, int off, int len, byte[] dest, int destoff) { int c, count = destoff; for (int i = 0; i < len; i++) { c = s[i]; if ((c >= 0x0001) && (c <= 0x007F)) { dest[count++] = (byte) c; } else if (c > 0x07FF) { dest[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F)); dest[count++] = (byte) (0x80 | ((c >> 6) & 0x3F)); dest[count++] = (byte) (0x80 | ((c >> 0) & 0x3F)); } else { dest[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F)); dest[count++] = (byte) (0x80 | ((c >> 0) & 0x3F)); } } } /** * Reads UTF-8 encoded character array from an input stream. * @param in the input stream to read from * @return decoded character array * @throws IOException if I/O error occurs */ public final static char[] readUTF(InputStream in) throws IOException { DataInput din = (in instanceof DataInput) ? (DataInput)in : new DataInputStream(in); return readUTF(din); } /** * Reads UTF-8 encoded character array from a data input. * @param in the data input to read from * @return decoded character array * @throws IOException if I/O error occurs */ public final static char[] readUTF(DataInput in) throws IOException { int utflen = in.readUnsignedShort(); byte bytearr[] = new byte[utflen]; try { in.readFully(bytearr, 0, utflen); return fromUTF(bytearr); } finally { Arrays.fill(bytearr, (byte)0); } } /** * Recovers a character array out of its UTF-8 encoding. * * @param utfString containing UTF-8-encoded character array * @return the decoded character array * @throws IOException if I/O error occurs */ public final static char[] fromUTF(final byte[] utfString) throws IOException { return fromUTF(utfString, 0, utfString.length); } /** * Recovers a character array out of its UTF-8 encoding. * * @param utfString array containing UTF-8-encoded character array * @param off start offset within utfString * @param len number of bytes to include * @return the decoded character array * @throws IOException if I/O error occurs */ public final static char[] fromUTF(final byte[] utfString, int off, int len) throws IOException { char[] arr = new char[len]; int c, char2, char3; int idx = 0; try { while (off < len) { c = (int) utfString[off] & 0xff; switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: /* 0xxxxxxx*/ off++; arr[idx++] = (char) c; break; case 12: case 13: /* 110x xxxx 10xx xxxx*/ off += 2; if (off > len) throw new UTFDataFormatException(); char2 = (int) utfString[off - 1]; if ( (char2 & 0xC0) != 0x80) throw new UTFDataFormatException(); arr[idx++] = (char) ( ( (c & 0x1F) << 6) | (char2 & 0x3F)); break; case 14: /* 1110 xxxx 10xx xxxx 10xx xxxx */ off += 3; if (off > len) throw new UTFDataFormatException(); char2 = (int) utfString[off - 2]; char3 = (int) utfString[off - 1]; if ( ( (char2 & 0xC0) != 0x80) || ( (char3 & 0xC0) != 0x80)) throw new UTFDataFormatException(); arr[idx++] = (char) ( ( (c & 0x0F) << 12) | ( (char2 & 0x3F) << 6) | ( (char3 & 0x3F) << 0)); break; default: /* 10xx xxxx, 1111 xxxx */ throw new UTFDataFormatException(); } } // The number of chars produced may be less than utflen if (idx < len) { char[] newarr = new char[idx]; System.arraycopy(arr, 0, newarr, 0, idx); Arrays.fill(arr, (char)0); arr = newarr; } return arr; } catch (IOException e) { Arrays.fill(arr, (char)0); throw e; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy