/** * Licensed to The Apereo Foundation under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * * The Apereo Foundation licenses this file to you under the Educational * Community 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://opensource.org/licenses/ecl2.txt * * 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.opencastproject.util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.security.Key; import java.security.MessageDigest; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.crypto.spec.SecretKeySpec; /** AES encryption. */ public final class Crypt { private Crypt() { } public static String encrypt(Key key, String text) { final ByteArrayOutputStream encrypted; try { final Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, key); encrypted = new ByteArrayOutputStream(); final CipherOutputStream cipherStream = new CipherOutputStream(encrypted, cipher); try { cipherStream.write(text.getBytes()); } finally { try { cipherStream.close(); } catch (Exception e) { } try { encrypted.close(); } catch (Exception e) { } } } catch (Exception e) { throw new RuntimeException("Error encrypting text", e); } return new String(encodeToHex(encrypted.toByteArray())); } public static String decrypt(Key key, String encryptedText) { final ByteArrayOutputStream decrypted; try { final Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, key); final byte[] decodeBuffer = new byte[1024]; final ByteArrayInputStream encrypted = new ByteArrayInputStream(decodeFromHex(encryptedText)); decrypted = new ByteArrayOutputStream(); final CipherInputStream cipherStream = new CipherInputStream(encrypted, cipher); try { int n; while ((n = cipherStream.read(decodeBuffer)) > 0) { decrypted.write(decodeBuffer, 0, n); } } finally { IoSupport.closeQuietly(decrypted); IoSupport.closeQuietly(cipherStream); IoSupport.closeQuietly(encrypted); } } catch (Exception e) { throw new RuntimeException("Error decrypting text", e); } return decrypted.toString(); } public static Key createKey(String password) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(password.getBytes("ISO-8859-1")); return new SecretKeySpec(md.digest(), "AES"); } catch (Exception e) { throw new RuntimeException("Error creating key", e); } } // Copied here so that the Security methods can be run standalone without dependencies private static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; public static char[] encodeToHex(byte[] bytes) { final int nBytes = bytes.length; char[] result = new char[2 * nBytes]; int j = 0; for (int i = 0; i < nBytes; i++) { // Char for top 4 bits result[j++] = HEX[(0xF0 & bytes[i]) >>> 4]; // Bottom 4 result[j++] = HEX[(0x0F & bytes[i])]; } return result; } public static byte[] decodeFromHex(CharSequence s) { int nChars = s.length(); if (nChars % 2 != 0) { throw new IllegalArgumentException("Hex-encoded string must have an even number of characters"); } byte[] result = new byte[nChars / 2]; for (int i = 0; i < nChars; i += 2) { int msb = Character.digit(s.charAt(i), 16); int lsb = Character.digit(s.charAt(i + 1), 16); if (msb < 0 || lsb < 0) { throw new IllegalArgumentException("Non-hex character in input: " + s); } result[i / 2] = (byte) ((msb << 4) | lsb); } return result; } }