/*
* Freeplane - mind map editor
* Copyright (C) 2008 Dimitry Polivaev
*
* This file author is Dimitry Polivaev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.freeplane.features.encrypt;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import org.freeplane.core.util.LogUtils;
import org.freeplane.features.map.IEncrypter;
/**
* @author Dimitry Polivaev
* 29.12.2008
*/
public class DesEncrypter implements IEncrypter {
private static final int SALT_LENGTH = 8;
private static final String SALT_PRESENT_INDICATOR = " ";
/**
* @throws IOException
*/
public static byte[] fromBase64(final String base64String) {
return Base64Coding.decode64(base64String);
}
/**
*/
public static String toBase64(final byte[] byteBuffer) {
return Base64Coding.encode64(byteBuffer);
}
private Cipher dcipher;
private Cipher ecipher;
int iterationCount = 19;
final private String mAlgorithm;
byte[] mSalt = { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3,
(byte) 0x03 };
private char[] passPhrase;
public DesEncrypter(final StringBuilder pPassPhrase, final String pAlgorithm) {
passPhrase = new char[pPassPhrase.length()];
pPassPhrase.getChars(0, passPhrase.length, passPhrase, 0);
mAlgorithm = pAlgorithm;
}
public String decrypt(String str) {
if (str == null) {
return null;
}
try {
byte[] salt = null;
final int indexOfSaltIndicator = str.indexOf(DesEncrypter.SALT_PRESENT_INDICATOR);
if (indexOfSaltIndicator >= 0) {
final String saltString = str.substring(0, indexOfSaltIndicator);
str = str.substring(indexOfSaltIndicator + 1);
salt = DesEncrypter.fromBase64(saltString);
}
final byte[] dec = DesEncrypter.fromBase64(str);
init(salt);
if (dcipher == null) {
return null;
}
final byte[] utf8 = dcipher.doFinal(dec);
return new String(utf8, "UTF8");
}
catch (final javax.crypto.BadPaddingException e) {
}
catch (final IllegalBlockSizeException e) {
}
catch (final UnsupportedEncodingException e) {
}
catch (final IllegalArgumentException e) {
}
return null;
}
public String encrypt(final String str) {
try {
initWithNewSalt();
if(ecipher == null)
return null;
final byte[] utf8 = str.getBytes("UTF8");
final byte[] enc = ecipher.doFinal(utf8);
return DesEncrypter.toBase64(mSalt) + DesEncrypter.SALT_PRESENT_INDICATOR + DesEncrypter.toBase64(enc);
}
catch (final javax.crypto.BadPaddingException e) {
}
catch (final IllegalBlockSizeException e) {
}
catch (final UnsupportedEncodingException e) {
}
return null;
}
public void initWithNewSalt() {
final byte[] newSalt = new byte[DesEncrypter.SALT_LENGTH];
for (int i = 0; i < newSalt.length; i++) {
newSalt[i] = (byte) (Math.random() * 256l - 128l);
}
init(newSalt);
}
/**
*/
private void init(final byte[] salt) {
if (ecipher != null && mSalt != null && !Arrays.equals(mSalt, salt)) {
ecipher = null;
dcipher = null;
}
if (salt != null) {
mSalt = salt;
}
if (ecipher == null) {
try {
SecretKey key;
try{
KeySpec keySpec = new PBEKeySpec(passPhrase, mSalt, iterationCount);
key = SecretKeyFactory.getInstance(mAlgorithm).generateSecret(keySpec);
}
catch (final java.security.spec.InvalidKeySpecException e) {
try {
passPhrase = URLEncoder.encode(new String(passPhrase), "UTF-8").toCharArray();
}
catch (UnsupportedEncodingException e1) {
throw e;
}
KeySpec keySpec = new PBEKeySpec(passPhrase, mSalt, iterationCount);
key = SecretKeyFactory.getInstance(mAlgorithm).generateSecret(keySpec);
}
ecipher = Cipher.getInstance(mAlgorithm);
dcipher = Cipher.getInstance(mAlgorithm);
final AlgorithmParameterSpec paramSpec = new PBEParameterSpec(mSalt, iterationCount);
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
}
catch (final java.security.InvalidAlgorithmParameterException e) {
LogUtils.severe(e);
}
catch (final java.security.spec.InvalidKeySpecException e) {
LogUtils.severe(e);
}
catch (final javax.crypto.NoSuchPaddingException e) {
LogUtils.severe(e);
}
catch (final java.security.NoSuchAlgorithmException e) {
LogUtils.severe(e);
}
catch (final java.security.InvalidKeyException e) {
LogUtils.severe(e);
}
}
}
}