Java tutorial
package org.fnppl.opensdx.security; /* * Copyright (C) 2010-2015 * fine people e.V. <opensdx@fnppl.org> * Henning Thie <ht@fnppl.org> * * http://fnppl.org */ /* * Software license * * As far as this file or parts of this file is/are software, rather than documentation, this software-license applies / shall be applied. * * This file is part of openSDX * openSDX is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * openSDX is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * and GNU General Public License along with openSDX. * If not, see <http://www.gnu.org/licenses/>. * */ /* * Documentation license * * As far as this file or parts of this file is/are documentation, rather than software, this documentation-license applies / shall be applied. * * This file is part of openSDX. * Permission is granted to copy, distribute and/or modify this document * under the terms of the GNU Free Documentation License, Version 1.3 * or any later version published by the Free Software Foundation; * with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. * A copy of the license is included in the section entitled "GNU * Free Documentation License" resp. in the file called "FDL.txt". * */ import java.io.*; import java.math.BigInteger; import java.util.*; import java.security.*; import org.bouncycastle.crypto.engines.*; import org.bouncycastle.crypto.*; import org.bouncycastle.crypto.modes.*; import org.bouncycastle.crypto.encodings.*; import org.bouncycastle.crypto.paddings.*; import org.bouncycastle.crypto.params.*; //import com.sun.crypto.provider.AESCipher; import com.sun.org.apache.bcel.internal.generic.AASTORE; /* * hrmpf. most probably not used in this context - hooray for Rijndael_256 !!! */ /* * @author Henning Thie <ht@fnppl.org> * */ public class SymmetricKey { static { SecurityHelper.ensureBC(); } private final static int keybits = 256;//ok, doing so fails the aes128-rule and may fall into US-weapons-regulation private final static int blockbits = 128; private byte[] initVector = null; private byte[] keyBytes = null; private final byte[] my_buff = new byte[16]; private final byte[] my_buff2 = new byte[48]; PaddedBufferedBlockCipher aesCipher = null; private int blockSize = -1; public SymmetricKey(byte[] key_bytes, byte[] iv) { this.keyBytes = key_bytes; this.initVector = iv; CBCBlockCipher aesCBC = new CBCBlockCipher(new AESEngine()); KeyParameter kp = new KeyParameter(keyBytes); ParametersWithIV aesCBCParams = new ParametersWithIV(kp, initVector); aesCipher = new PaddedBufferedBlockCipher(aesCBC, new PKCS7Padding()); aesCipher.init(true, aesCBCParams); blockSize = aesCipher.getBlockSize(); } public static SymmetricKey getRandomKey() { SecureRandom sc = new SecureRandom();//TODO HT 20.02.2011 - quite good, but should swirl it twice with tiger, or aes/rijndael itself byte[] aes_key_bytes = new byte[keybits / 8]; //yep. please be aware of non-8-dividable bits - however, should be 128 for various reasons byte[] iv = new byte[blockbits / 8]; sc.nextBytes(aes_key_bytes); sc.nextBytes(iv); //now should swirl those byte one more time... return new SymmetricKey(aes_key_bytes, iv); } public static SymmetricKey getKeyFromPass(char[] pass, byte[] iv) throws Exception { if (iv.length != blockbits / 8) { throw new RuntimeException("Invalid InitVector-Size: " + iv.length + " expected: " + (blockbits / 8)); } byte[] aes_key_bytes = new byte[keybits / 8]; byte[] sha256 = SecurityHelper.getSHA256(String.valueOf(pass).getBytes("UTF-8")); //System.err.println("getKeyFromPass:: ll.length:"+sha256.length+"\taes_key_bytes.length:"+aes_key_bytes.length); for (int i = 0; i < aes_key_bytes.length; i++) { aes_key_bytes[i] = sha256[i]; } SymmetricKey sk = new SymmetricKey(aes_key_bytes, iv); //System.out.println("INITVECTOR: "+SecurityHelper.HexDecoder.encode(sk.initVector,':',-1)); //System.out.println("KEY: "+SecurityHelper.HexDecoder.encode(sk.keyBytes,':',-1)); return sk; } // public byte[] encrypt(byte[] in) throws Exception { // int blockSize = aesCipher.getBlockSize(); // byte[] cipherTextBlock = new byte[blockSize]; // int size = aesCipher.getOutputSize(in.length); // // byte[] result = new byte[size]; // int olen = aesCipher.processBytes(in, 0, in.length, result, 0); // olen += aesCipher.doFinal(result, olen); // // // if (olen < size) { // System.out.println("SymmetricKey::encrypt::olen!=size: "+olen+"!="+size); // // byte[] tmp = new byte[olen]; // System.arraycopy(result, 0, tmp, 0, olen); // result = tmp; // } // // return result; // } public int encrypt(byte[] in, byte[] out) throws Exception { int size = aesCipher.getOutputSize(in.length); if (out.length < size) { throw new Exception("outbuffer.size(" + out.length + ") too small to hold " + size + " bytes"); } int olen = aesCipher.processBytes(in, 0, in.length, out, 0); olen += aesCipher.doFinal(out, olen); if (olen < size) { System.out.println("SymmetricKey::encrypt::olen!=size: " + olen + "!=" + size); // // byte[] tmp = new byte[olen]; // System.arraycopy(result, 0, tmp, 0, olen); // result = tmp; } return olen; } public void encrypt(InputStream in, OutputStream out) throws Exception { int read = -1; int or = 0; int rr = 0; while ((read = in.read(my_buff)) != -1) { rr += read; int rg = aesCipher.processBytes(my_buff, 0, read, my_buff2, 0); // System.err.println("READ: "+read); // System.err.println("PROCESS_BYTES_RETURN: "+rg); out.write(my_buff2, 0, rg); or += rg; } // int oss = aesCipher.getOutputSize(rr); // System.err.println("BYTES_WRITTEN_OVERALL: "+or); // System.err.println("BYTES_READ_OVERALL: "+rr); // System.err.println("AESCIPHER.getOutputSize("+rr+"): "+oss); // int rest = oss - or; read = aesCipher.doFinal(my_buff2, 0); // System.err.println("READ_LAST: "+read); out.write(my_buff2, 0, read); } // //TODO HT 2013-10-11 optimize for direct byte-buffer !!! // public byte[] encrypt(byte[] b) throws Exception { // ByteArrayOutputStream out = new ByteArrayOutputStream(); // encrypt(new ByteArrayInputStream(b), out); // return out.toByteArray(); // } public byte[] decrypt(byte[] b) throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); decrypt(new ByteArrayInputStream(b), out); return out.toByteArray(); } public void decrypt(InputStream in, OutputStream out) throws Exception { // if(key.length!=initvector.length || key.length!=keybits/8) { // throw new Exception("invalid params"); // } CBCBlockCipher aesCBC = new CBCBlockCipher(new AESEngine()); KeyParameter kp = new KeyParameter(keyBytes); ParametersWithIV aesCBCParams = new ParametersWithIV(kp, initVector); PaddedBufferedBlockCipher aesCipher = new PaddedBufferedBlockCipher(aesCBC, new PKCS7Padding()); aesCipher.init(false, aesCBCParams); // aesCipher.init(true, aesCBCParams); //TODO pad block corrupted error when false. WHY?? int read = -1; byte[] buff = new byte[128 / 8];//blocksize while ((read = in.read(buff)) != -1) { byte[] ou = new byte[buff.length]; // System.err.println("read: "+read); int rg = aesCipher.processBytes(buff, 0, read, ou, 0); out.write(ou, 0, rg); // System.err.println("rg: "+rg); } buff = new byte[2 * 128 / 8];//blocksize read = aesCipher.doFinal(buff, 0); out.write(buff, 0, read); } public byte[] getInitVector() { return initVector; } public byte[] getKeyBytes() { return keyBytes; } public static void main(String[] args) throws Exception { //test encryption of private key AsymmetricKeyPair akp = AsymmetricKeyPair.generateAsymmetricKeyPair(); String initv = "00112233445566778899AABBCCDDEEFF"; String pp = "password"; SymmetricKey sk = SymmetricKey.getKeyFromPass(pp.toCharArray(), SecurityHelper.HexDecoder.decode(initv)); byte[] encPrivKey = akp.getEncrytedPrivateKey(sk); byte[] decPrivKey = sk.decrypt(encPrivKey); System.out.println( "PUB_KEY_MODULUS : " + SecurityHelper.HexDecoder.encode(akp.getPublicModulus(), ':', -1)); System.out .println("PUB_KEY_EXP : " + SecurityHelper.HexDecoder.encode(akp.getPublicExponent(), ':', -1)); System.out.println("ENC_PRIV_KEY_EXP: " + SecurityHelper.HexDecoder.encode(encPrivKey, ':', -1)); System.out.println("DEC_PRIV_KEY_EXP: " + SecurityHelper.HexDecoder.encode(decPrivKey, ':', -1)); System.out.println("keyid : " + akp.getKeyID()); // SymmetricKey l = SymmetricKey.getRandomKey(); // System.out.println("INITVECTOR: "+SecurityHelper.HexDecoder.encode(l.initVector,':',-1)); // System.out.println("KEY: "+SecurityHelper.HexDecoder.encode(l.keyBytes,':',-1)); // byte[] sha256 = SecurityHelper.getSHA256(String.valueOf(pp.toCharArray()).getBytes("UTF-8")); // System.out.println("pass: "+pp); // System.out.println("key: "+SecurityHelper.HexDecoder.encode(sha256,'\0',-1)); // INITVECTOR: 1D8BEE695B7F4EFF6F7B947F1B197B97 // KEY: 9034F3A02E7DBD9870D7FC23FCD0E3CA5B9292F7F2314B495DBF042078632B24 // byte[] key = SecurityHelper.HexDecoder.decode("9034F3A02E7DBD9870D7FC23FCD0E3CA5B9292F7F2314B495DBF042078632B24"); // byte[] init = SecurityHelper.HexDecoder.decode("2A8BEE695B7F4EFF6F7B947F1B197B97"); // // SymmetricKey l = new SymmetricKey(key, init); //// byte[] test = "ich asda will encoded werden...".getBytes(); // byte[] test = "ich".getBytes(); // // ByteArrayOutputStream bout = new ByteArrayOutputStream(); // // ByteArrayInputStream bin = new ByteArrayInputStream(test); // bout.reset(); // sk.encrypt(bin, bout); // // byte[] enc = bout.toByteArray(); byte[] enc = new byte[512]; // byte[] enc = sk.encrypt(test); int r = sk.encrypt(test, enc); byte[] enc_t = new byte[r]; System.arraycopy(enc, 0, enc_t, 0, r); byte[] dec = sk.decrypt(enc_t); System.out.println("BEFORE: " + (new String(test))); System.out.println("ENC: " + SecurityHelper.HexDecoder.encode(enc_t, ':', -1)); System.out.println("AFTER: " + (new String(dec))); } }