/* * Copyright 2011 David Brazdil * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package uk.ac.cam.db538.cryptosms.utils; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import org.spongycastle.crypto.RuntimeCryptoException; import uk.ac.cam.db538.cryptosms.crypto.Encryption; /* * Class with static methods for encoding/decoding text in different charsets */ public class Charset { private static final String CHARSET_ASCII = "US-ASCII"; /** * Checks whether each character in String is representable by 7-bit ASCII. * * @param text the text * @return true, if is convertable to ascii */ public static boolean isConvertableToAscii(String text) { for (int i = 0; i < text.length(); ++i) if (text.charAt(i) > 127) return false; return true; } /** * Computes how many bytes a text would occupy if it was * encoded in 7-bit ASCII. * * @param text the text * @return the int */ public static int computeLengthInAscii7(String text) { int len = text.length(); return 7 * len / 8 + ((len % 8 == 0) ? 0 : 1); } /** * Turns a string into a series of bytes. * @param text Encoded string * @param bufferLength Maximum size of the resulting array * @param charset Resulting charset * @return */ private static byte[] toBytes(String text, int bufferLength, String charset) { ByteBuffer buffer = ByteBuffer.allocate(bufferLength); byte[] latin = null; try { latin = text.getBytes(charset); } catch (UnsupportedEncodingException e) { return null; } if (latin.length < bufferLength) { buffer.put(latin); buffer.put((byte) 0x00); buffer.put(Encryption.getEncryption().generateRandomData(bufferLength - latin.length - 1)); } else buffer.put(latin, 0, bufferLength); return buffer.array(); } /** * Takes a byte array with characters in it, and turns it into a string * @param bytesData Data to be processed * @param offset Offset in the array * @param len Length of data * @return */ private static String fromBytes(byte[] bytesData, int offset, int len, String charset) { int length = 0; while (length < len && bytesData[offset + length] != 0) ++length; try { return new String(bytesData, offset, Math.min(len, length), CHARSET_ASCII); } catch (UnsupportedEncodingException ex) { return null; } } /** * Turns a string into an 8-bit ASCII series of bytes. * * @param text Encoded string * @return the byte[] */ public static byte[] toAscii8(String text) { return toAscii8(text, text.length()); } /** * Turns a string into an 8-bit ASCII series of bytes. * * @param text Encoded string * @param bufferLength Maximum size of the resulting array * @return the byte[] */ public static byte[] toAscii8(String text, int bufferLength) { return toBytes(text, bufferLength, CHARSET_ASCII); } /** * Takes a byte array with 8-bit ASCII characters in it, and turns it into a string. * * @param latinData Data to be processed * @return the string */ public static String fromAscii8(byte[] latinData) { return fromAscii8(latinData, 0, latinData.length); } /** * Takes a byte array with 8-bit ASCII characters in it, and turns it into a string. * * @param latinData Data to be processed * @param offset Offset in the array * @param len Length of data * @return the string */ public static String fromAscii8(byte[] latinData, int offset, int len) { return fromBytes(latinData, offset, len, CHARSET_ASCII); } /** * Turns a string into an 7-bit ASCII series of bytes. * * @param text Encoded string * @return the byte[] */ public static byte[] toAscii7(String text) { return toAscii7(text, computeLengthInAscii7(text)); } /** * Turns a string into an 7-bit ASCII series of bytes. * * @param text Encoded string * @param bufferLength Maximum size of the resulting array * @return the byte[] */ public static byte[] toAscii7(String text, int bufferLength) { int bigLength = text.length(); byte[] asciiData = toBytes(text, bigLength + 1, CHARSET_ASCII); // +1 is for the ending zero byte[] compressedData = new byte[bufferLength]; for (int i = 0; i < bufferLength; ++i) compressedData[i] = (byte) 0x00; int posCompressed = 0; int start = 7; for (int i = 0; i < bigLength; ++i) { if (start == 7) { // only position where space is left after the filling compressedData[posCompressed] = (byte) (asciiData[i] << 1); start = 0; } else { compressedData[posCompressed++] |= (byte) (asciiData[i] >> (6 - start)); if (start != 6) compressedData[posCompressed] |= (byte) (asciiData[i] << (2 + start)); ++start; } } return compressedData; } /** * Takes a byte array with 7-bit ASCII characters in it, and turns it into a string. * * @param asciiData Data to be processed * @return the string */ public static String fromAscii7(byte[] asciiData) { return fromAscii7(asciiData, 0, asciiData.length); } /** * Takes a byte array with 7-bit ASCII characters in it, and turns it into a string. * * @param compressedData the compressed data * @param offset Offset in the array * @param len Length of data * @return the string */ public static String fromAscii7(byte[] compressedData, int offset, int len) { int bufferLength = len; int bigLength = 8 * bufferLength / 7 + ((bufferLength % 7 == 0) ? 0 : 1); byte[] asciiData = new byte[bigLength + 1]; // +1 is for the ending zero for (int i = 0; i < bigLength + 1; ++i) asciiData[i] = (byte) 0x00; int posCompressed = 0; int start = 7; int temp; for (int i = 0; posCompressed < compressedData.length; ++i) { if (start == 7) { // only position where all the data fit in one byte asciiData[i] = (byte) (((int) compressedData[offset + posCompressed] & 0xFF) >> 1); start = 0; } else { temp = ((((int)compressedData[posCompressed++]) & 0xFF) << (6 - start)) & 0x7F; if (start != 6 && posCompressed < compressedData.length) temp |= ((((int)compressedData[posCompressed]) & 0xFF) >> (2 + start)) & 0x7F; asciiData[i] = (byte) temp; ++start; } } return fromBytes(asciiData, 0, bigLength + 1, CHARSET_ASCII); } /** * Turns a string into a Unicode series of bytes. * * @param text Encoded string * @return the byte[] */ public static byte[] toUTF16(String text) { try { return text.getBytes("UTF-16"); } catch (UnsupportedEncodingException e) { throw new RuntimeCryptoException(); } } /** * Takes a byte array with Unicode characters in it, and turns it into a string. * * @param utfData Data to be processed * @return the string */ public static String fromUTF16(byte[] utfData) { try { return new String(utfData, "UTF-16"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } /** * Turns a string into a Unicode series of bytes. * * @param text Encoded string * @return the byte[] */ public static byte[] toUTF8(String text) { try { return text.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } /** * Takes a byte array with Unicode characters in it, and turns it into a string. * * @param utfData Data to be processed * @return the string */ public static String fromUTF8(byte[] utfData) { try { return new String(utfData, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } }