Verschlüsselung

Ich habe das Thema Verschlüsselung gekapselt, um unabhängig von der entsprechenden Implementierung zu sein und zusätzlich durch eine zunächst abstrakte Implementierung die Möglichkeit zu haben, ohne großen Aufwand die Verschlüsselungsmethode in einer Anwendung zu ändern. Daher habe ich zuerst das Interface Crypt erstellt.

package de.volkerfaas.crypto;

public interface Crypt {

    String encrypt(String string) throws Exception;
    String decrypt(String string) throws Exception;
    void setKey(String key) throws Exception;
    void setEncoding(String encoding);
    void setEncoding(Encoding encoding);

    public enum Encoding {
        BASE64, HEX
    }
}

Die Implementierung diese Interfaces erfolgt zunächst unabhängig von den Verschlüsselungsmethoden als abstrakte Klasse und basiert auf Java Ciphering. Der Schlüssel wird in der Datei crypto.key im Classpath abgelegt und besteht aus einer beliebigen  Zeichenfolge. Die Länge der Zeichenfolge hängt von der jeweiligen Implementierung ab.

package de.volkerfaas.crypto;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.FileUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.spec.AlgorithmParameterSpec;

abstract class AbstractCrypt implements Crypt {

    protected static final String UNICODE_FORMAT = "UTF8";

    private AlgorithmParameterSpec parameterSpec;
    private Cipher cipher;
    private SecretKey secretKey;
    private Encoding encoding;

    AbstractCrypt(String algorithm, byte[] iv) throws Exception {
        this.cipher = Cipher.getInstance(algorithm);
        this.encoding = Encoding.BASE64;
        this.parameterSpec = new IvParameterSpec(iv);

        Resource keyResource = new ClassPathResource("crypto.key");
        final File keyResourceFile = keyResource.getFile();
        if (keyResourceFile.exists()) {
            String key = FileUtils.readFileToString(keyResourceFile, UNICODE_FORMAT);
            setKey(key);
        }


    }

    final void setSecretKey(SecretKey secretKey) {
        this.secretKey = secretKey;
    }

    @Override
    public final void setEncoding(String encoding) {
        this.encoding = Encoding.valueOf(encoding);
    }

    @Override
    public void setEncoding(Encoding encoding) {
        this.encoding = encoding;
    }

    @Override
    public final String encrypt(String string) throws InvalidKeyException, UnsupportedEncodingException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
        byte[] bytes = string.getBytes(UNICODE_FORMAT);
        byte[] cipheredBytes = cipher.doFinal(bytes);

        return encode(cipheredBytes, encoding);
    }

    @Override
    public final String decrypt(String string) throws InvalidKeyException, BadPaddingException, IllegalBlockSizeException, DecoderException, IOException, InvalidAlgorithmParameterException {
        cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec);
        byte[] cipheredBytes = decode(string, encoding);
        byte[] bytes = cipher.doFinal(cipheredBytes);

        return new String(bytes);
    }

    private String encode(byte[] bytes, Encoding encoding) throws UnsupportedEncodingException {
        if (Encoding.BASE64.equals(encoding)) {
            return new BASE64Encoder().encode(bytes);
        } else if (Encoding.HEX.equals(encoding)) {
            return Hex.encodeHexString(bytes);
        }

        throw new UnsupportedEncodingException("Encoding not supported.");
    }

    private byte[] decode(String string, Encoding encoding) throws IOException, DecoderException {
        if (Encoding.BASE64.equals(encoding)) {
            return new BASE64Decoder().decodeBuffer(string);
        } else if (Encoding.HEX.equals(encoding)) {
            return Hex.decodeHex(string.toCharArray());
        }

        throw new UnsupportedEncodingException("Encoding not supported.");
    }

}

Zur Implementierung z.B. des DES Verschlüsselungsmechanismus wird dann eine Klasse von AbstractCrypt abgeleitet. In diesem Fall muss noch die Methode setKey überschrieben werden, da für den Verschlüsselungsmechanismus noch ein Secret erstellt werden muss. Hier ist zu beachten, dass der in der Datei crypto.key hinterlegte Schlüssel mindestens 8 Zeichen betragen muss, da zur Erstellung des Secret die ersten 8 Bytes verwendet werden.

package de.volkerfaas.crypto;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;

public class DesCrypt extends AbstractCrypt {

    private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding";
    private static final String KEY_ALGORITHM = "DES";
    private static byte[] IV = {
            (byte) 0xB2, (byte) 0x12, (byte) 0xD5, (byte) 0xB2,
            (byte) 0x44, (byte) 0x21, (byte) 0xC3, (byte) 0xC3
    };

    public DesCrypt() throws Exception {
        super(CIPHER_ALGORITHM, IV);
    }

    @Override
    public void setKey(String key) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
        super.setSecretKey(SecretKeyFactory.getInstance(KEY_ALGORITHM).generateSecret(new DESKeySpec(key.getBytes(UNICODE_FORMAT))));
    }

}

Ein konkreter Anwendungsfall des DES Verschlüsselungsmechanismus ist im Beitrag Umgebungsunabhängige Konfiguration beschrieben.

Schreibe einen Kommentar