Java tutorial
/** * * Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com> * * ==================================================================== * 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 org.jclouds.crypto; import static com.google.common.base.Preconditions.checkNotNull; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import javax.crypto.Mac; import org.jclouds.encryption.internal.Base64; import org.jclouds.io.InputSuppliers; import com.google.common.annotations.Beta; import com.google.common.base.Charsets; import com.google.common.base.Throwables; import com.google.common.io.ByteProcessor; import com.google.common.io.ByteStreams; import com.google.common.io.InputSupplier; /** * functions related to but not in {@link com.google.common.io.ByteStreams} * * @author Adrian Cole */ @Beta public class CryptoStreams { public static String hex(byte[] in) { byte[] hex = new byte[2 * in.length]; int index = 0; for (byte b : in) { int v = b & 0xFF; hex[index++] = HEX_CHAR_TABLE[v >>> 4]; hex[index++] = HEX_CHAR_TABLE[v & 0xF]; } try { return new String(hex, "ASCII"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } public static byte[] hex(String s) { int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); } return data; } public static String base64(byte[] in) { return Base64.encodeBytes(in, Base64.DONT_BREAK_LINES); } public static byte[] base64(String in) { return Base64.decode(in); } /** * @see #md5 * @see #hex */ public static String md5Hex(InputSupplier<? extends InputStream> supplier) throws IOException { return hex(md5(supplier)); } /** * @see #md5 * @see #base64 */ public static String md5Base64(InputSupplier<? extends InputStream> supplier) throws IOException { return base64(md5(supplier)); } /** * Computes and returns the MAC value for a supplied input stream. The mac object is reset when * this method returns successfully. * * @param supplier * the input stream factory * @param mac * the mac object * @return the result of {@link Mac#doFinal()} after updating the mac object with all of the * bytes in the stream and encoding in Base64 * @throws IOException * if an I/O error occurs */ public static String macBase64(InputSupplier<? extends InputStream> supplier, final Mac mac) throws IOException { return base64(mac(supplier, mac)); } /** * Computes and returns the Digest value for a supplied input stream. The digest object is reset * when this method returns successfully. * * @param supplier * the input stream factory * @param md * the digest object * @return the result of {@link MessageDigest#digest()} after updating the digest object with all * of the bytes in the stream * @throws IOException * if an I/O error occurs */ public static byte[] digest(InputSupplier<? extends InputStream> supplier, final MessageDigest md) throws IOException { return com.google.common.io.ByteStreams.readBytes(supplier, new ByteProcessor<byte[]>() { public boolean processBytes(byte[] buf, int off, int len) { md.update(buf, off, len); return true; } public byte[] getResult() { return md.digest(); } }); } /** * Computes and returns the MD5 value for a supplied input stream. A digest object is created and * disposed of at runtime, consider using {@link #digest} to be more efficient. * * @param supplier * the input stream factory * * @return the result of {@link MessageDigest#digest()} after updating the md5 object with all of * the bytes in the stream * @throws IOException * if an I/O error occurs */ public static byte[] md5(InputSupplier<? extends InputStream> supplier) throws IOException { try { return digest(supplier, MessageDigest.getInstance("MD5")); } catch (NoSuchAlgorithmException e) { Throwables.propagate(e); return null; } } public static byte[] md5(byte[] in) throws IOException { return md5(ByteStreams.newInputStreamSupplier(in)); } /** * Computes and returns the MAC value for a supplied input stream. The mac object is reset when * this method returns successfully. * * @param supplier * the input stream factory * @param mac * the mac object * @return the result of {@link Mac#doFinal()} after updating the mac object with all of the * bytes in the stream * @throws IOException * if an I/O error occurs */ public static byte[] mac(InputSupplier<? extends InputStream> supplier, final Mac mac) throws IOException { return com.google.common.io.ByteStreams.readBytes(checkNotNull(supplier, "supplier"), new ByteProcessor<byte[]>() { public boolean processBytes(byte[] buf, int off, int len) { mac.update(buf, off, len); return true; } public byte[] getResult() { return mac.doFinal(); } }); } /** * Computes and returns the base64 value for a supplied input stream. * * @param supplier * the input stream factory * * @return the result of base 64 encoding all of the bytes in the stream * @throws IOException * if an I/O error occurs */ public static String base64Encode(InputSupplier<? extends InputStream> supplier) throws IOException { final ByteArrayOutputStream out = new ByteArrayOutputStream(); return com.google.common.io.ByteStreams.readBytes(InputSuppliers.base64Encoder(supplier), new ByteProcessor<String>() { public boolean processBytes(byte[] buf, int off, int len) { out.write(buf, off, len); return true; } public String getResult() { return new String(out.toByteArray(), Charsets.UTF_8); } }); } /** * Computes and returns the unencoded value for an input stream which is encoded in Base64. * * @param supplier * the input stream factory * * @return the result of base 64 decoding all of the bytes in the stream * @throws IOException * if an I/O error occurs */ public static byte[] base64Decode(InputSupplier<? extends InputStream> supplier) throws IOException { final ByteArrayOutputStream out = new ByteArrayOutputStream(); return com.google.common.io.ByteStreams.readBytes(InputSuppliers.base64Decoder(supplier), new ByteProcessor<byte[]>() { public boolean processBytes(byte[] buf, int off, int len) { out.write(buf, off, len); return true; } public byte[] getResult() { return out.toByteArray(); } }); } final static byte[] HEX_CHAR_TABLE = { (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f' }; /** * Computes and returns the hex value for a supplied input stream. * * @param supplier * the input stream factory * * @return the result of hex encoding all of the bytes in the stream * @throws IOException * if an I/O error occurs */ public static String hexEncode(InputSupplier<? extends InputStream> supplier) throws IOException { final StringBuilder out = new StringBuilder(); return com.google.common.io.ByteStreams.readBytes(supplier, new ByteProcessor<String>() { public boolean processBytes(byte[] buf, int off, int len) { char[] hex = new char[2 * len]; int index = 0; for (int i = off; i < off + len; i++) { byte b = buf[i]; int v = b & 0xFF; hex[index++] = (char) HEX_CHAR_TABLE[v >>> 4]; hex[index++] = (char) HEX_CHAR_TABLE[v & 0xF]; } out.append(hex); return true; } public String getResult() { return out.toString(); } }); } /** * Computes and returns the unencoded value for an input stream which is encoded in hex. * * @param supplier * the input stream factory * * @return the result of hex decoding all of the bytes in the stream * @throws IOException * if an I/O error occurs */ public static byte[] hexDecode(InputSupplier<? extends InputStream> supplier) throws IOException { final ByteArrayOutputStream out = new ByteArrayOutputStream(); return com.google.common.io.ByteStreams.readBytes(supplier, new ByteProcessor<byte[]>() { int currentPos = 0; public boolean processBytes(byte[] buf, int off, int len) { try { if (currentPos == 0 && new String(Arrays.copyOfRange(buf, off, 2), "ASCII").equals("0x")) { off += 2; } byte[] decoded = hex(new String(Arrays.copyOfRange(buf, off, len), "ASCII")); out.write(decoded, 0, decoded.length); currentPos += len; } catch (UnsupportedEncodingException e) { throw new IllegalStateException("ASCII must be supported"); } return true; } public byte[] getResult() { return out.toByteArray(); } }); } }