Verwendung der Cipher von gnu crypto (Serpent)

  • Themenstarter Themenstarter MannMitBart
  • Beginndatum Beginndatum
M

MannMitBart

Gast
Hallo erstmal 🙂

Ich habe mir die gnu-crypto Bibliothek runtergeladen um eine kleine Cryptography-Klasse für mein Projekt zu erstellen.
Die Hash-Funktionen sind eigentlich nicht so schwer zu verstehen und waren nicht das Problem, allerdings versuche ich jetzt gerade auch eine Methode zum ver-/entschlüssen zu implementieren, an der ich nicht weiterkomme.
Mein Problem ist wohl eher auf verständnismäßiger Ebene.
Momentan wird soweit ich das verstanden habe nur ein einzige Block vom Input verschlüsselt und zurückgegeben.
Was ich haben möchte: input rein und das Ganze verschlüsselt wieder raus.
Könnt ihr mir eventuell weiterhelfen (hab irgendwie eine Denkblockade und ich sitze an diesem Problem wirklich schon peinlich lange...)?
(Google liefert mir immer nur JavaDocs... vielleicht frag ich auch nur das falsche :-X)

Code I use:
Java:
import java.security.InvalidKeyException;
import gnu.crypto.cipher.Serpent;
import gnu.crypto.hash.Sha512;
import gnu.crypto.hash.Whirlpool;

public class CryptographyModule{

	public static void main(String[] args) throws InvalidKeyException{
		String a="hallo du grausame welt der cryptographie :-O";
		byte[] key=get256BitHashFrom512BitHash(getWhirlpoolHash("passForHash".getBytes()));
		byte[] encrypted=encryptSerpent(a.getBytes(), key);
		System.out.println(new String(encrypted));
	}
	
	public static byte[] encryptSerpent(byte[] input, byte[] key) throws InvalidKeyException{
		Serpent serpent=new Serpent();
		byte[] output=new byte[serpent.defaultBlockSize()];
		Object sessionKey=serpent.makeKey(key, serpent.defaultBlockSize());
		serpent.encrypt(input, 0, output, 0, sessionKey, serpent.defaultBlockSize());
		return output;
	}
	
	
	public static byte[] getWhirlpoolHash(byte[] input){
		Whirlpool whirlpool=new Whirlpool();
		whirlpool.update(input, 0, input.length);
		return whirlpool.digest();
	}
	
	public static byte[] getSha512Hash(byte[] input){
		Sha512 sha512=new Sha512();
		sha512.update(input, 0, input.length);
		return sha512.digest();
	}
	
	public static byte[] get256BitHashFrom512BitHash(byte[] input){
		byte[] output=new byte[32];
		for(int i=0;i<32;i++){
			output[i]=input[i*2];
		}
		return output;
	}
	
}
 
Nach einigen herumprobieren und einer erneuten Recherche habe ich jetzt herausgefunden was ich falsch machte:

Der input zum Verschlüsseln muss immer ein vielfaches der Blockgröße des Verschlüsselungsalgorithmus sein. Das wird durch padding erreicht (das füllt vor dem verschlüsseln den input auf ein vielfaches der Blockgröße auf und entfernt diese angehängten Bytes nach dem entschlüsseln wieder).

Hier noch der Code der letztendlich rauskam:

Java:
import gnu.crypto.cipher.CipherFactory;
import gnu.crypto.cipher.IBlockCipher;
import gnu.crypto.hash.HashFactory;
import gnu.crypto.hash.IMessageDigest;
import gnu.crypto.pad.IPad;
import gnu.crypto.pad.PadFactory;
import gnu.crypto.pad.WrongPaddingException;
import java.security.InvalidKeyException;
import java.util.HashMap;
import java.util.Map;

public class CryptographyModule{
	
	public static final String CIPHER_ANUBIS="anubis";
	public static final String CIPHER_BLOWFISH="blowfish";
	public static final String CIPHER_CAST5="cast5";
	public static final String CIPHER_DES="des";
	public static final String CIPHER_KHAZAD="khazad";
	public static final String CIPHER_RIJNDAEL="rijndael";
	public static final String CIPHER_SERPENT="serpent";
	public static final String CIPHER_SQUARE="square";
	public static final String CIPHER_TRIPLEDES="tripledes";
	public static final String CIPHER_TWOFISH="twofish";
	public static final String HASH_HAVAL="haval";
	public static final String HASH_MD2="md2";
	public static final String HASH_MD4="md4";
	public static final String HASH_MD5="md5";
	public static final String HASH_RIPEMD128="ripemd128";
	public static final String HASH_SHA160="sha-160";
	public static final String HASH_SHA256="sha-256";
	public static final String HASH_SHA384="sha-384";
	public static final String HASH_SHA512="sha-512";
	public static final String HASH_TIGER="tiger";
	public static final String HASH_WHIRLPOOL="whirlpool";
	public static final String PAD_EME_PKCS1_v1_5="eme-pkcs1-v1.5";
	public static final String PAD_PKCS7="pkcs7";
	public static final String PAD_TBC="tbc";
	
	private static final String DEFAULT_CIPHER=CIPHER_SERPENT;
	private static final String DEFAULT_HASH=HASH_SHA256;
	private static final String DEFAULT_PAD=PAD_TBC;
	
	private CryptographyModule(){
	}
	
	public static byte[] encrypt(byte[] input, byte[] key) throws InvalidKeyException, IllegalStateException{
		return encrypt(input, key, DEFAULT_CIPHER, DEFAULT_HASH, DEFAULT_PAD);
	}
	
	public static byte[] encrypt(byte[] input, byte[] key, String cipherName, String hashName, String padName) throws InvalidKeyException, IllegalStateException{
		IBlockCipher iBlockCipher=CipherFactory.getInstance(cipherName);
		int blockSize=iBlockCipher.defaultBlockSize();
		Map<String, Object> attributes=new HashMap<String, Object>();
		attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, blockSize);
		attributes.put(IBlockCipher.KEY_MATERIAL, getHash(key, hashName));
		iBlockCipher.init(attributes);
		byte[] paddedInput=getPaddedData(input, PAD_TBC, blockSize);
		byte[] output=new byte[paddedInput.length];
		for(int i=0;i<paddedInput.length/blockSize;i++){
			iBlockCipher.encryptBlock(paddedInput, i*blockSize, output, i*blockSize);
		}
		return output;
	}
	
	public static byte[] decrypt(byte[] input, byte[] key) throws InvalidKeyException, IllegalStateException, WrongPaddingException{
		return decrypt(input, key, DEFAULT_CIPHER, DEFAULT_HASH, DEFAULT_PAD);
	}
	
	public static byte[] decrypt(byte[] input, byte[] key, String cipherName, String hashName, String padName) throws InvalidKeyException, IllegalStateException, WrongPaddingException{
		IBlockCipher iBlockCipher=CipherFactory.getInstance(cipherName);
		int blockSize=iBlockCipher.defaultBlockSize();
		Map<String, Object> attributes=new HashMap<String, Object>();
		attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, blockSize);
		attributes.put(IBlockCipher.KEY_MATERIAL, getHash(key, hashName));
		iBlockCipher.init(attributes);
		byte[] tempData=new byte[input.length];
		for(int i=0;i<input.length/blockSize;i++){
			iBlockCipher.decryptBlock(input, i*blockSize, tempData, i*blockSize);
		}
		return getUnpaddedData(tempData, padName, blockSize);
	}
	
	public static byte[] getHash(byte[] input, String hashName){
		IMessageDigest iMessageDigest=HashFactory.getInstance(hashName);
		iMessageDigest.update(input, 0, input.length);
		return iMessageDigest.digest();
	}
	
	public static byte[] getPaddedData(byte[] input, String padName, int blockSize){
		IPad iPad=PadFactory.getInstance(padName);
		iPad.init(blockSize);
		byte[] padSequence=iPad.pad(input, 0, input.length);
		byte[] output=new byte[input.length+padSequence.length];
		System.arraycopy(input, 0, output, 0, input.length);
		System.arraycopy(padSequence, 0, output, input.length, padSequence.length);
		return output;
	}
	
	public static byte[] getUnpaddedData(byte[] input, String padName, int blockSize) throws WrongPaddingException{
		IPad iPad=PadFactory.getInstance(padName);
		iPad.init(blockSize);
		int remove=iPad.unpad(input, 0, input.length);
		byte[] output=new byte[input.length-remove];
		System.arraycopy(input, 0, output, 0, output.length);
		return output;
	}
	
	public static boolean compareHashes(byte[] input1, byte[] input2){
		if(input1.length!=input2.length){
			return false;
		}
		else{
			for(int i=0;i<input1.length;i++){
				if(input1[i]!=input2[i]){
					return false;
				}
			}
		}
		return true;
	}
	
}

Ich hoffe das hilft auch anderen Kryptographie-Einsteigern in Java.

Mit freundlichen grüßen,
der MannMitBart
 
Da hatte sich ein kleiner Fehler eingeschlichen... der padName beim Verschlüsseln wurde ignoriert und immer TBC verwendet... sorry (kann als Gast leider nicht editieren wie es scheint)
Java:
import gnu.crypto.cipher.CipherFactory;
import gnu.crypto.cipher.IBlockCipher;
import gnu.crypto.hash.HashFactory;
import gnu.crypto.hash.IMessageDigest;
import gnu.crypto.pad.IPad;
import gnu.crypto.pad.PadFactory;
import gnu.crypto.pad.WrongPaddingException;
import java.security.InvalidKeyException;
import java.util.HashMap;
import java.util.Map;

public class CryptographyModule{
	
	public static final String CIPHER_ANUBIS="anubis";
	public static final String CIPHER_BLOWFISH="blowfish";
	public static final String CIPHER_CAST5="cast5";
	public static final String CIPHER_DES="des";
	public static final String CIPHER_KHAZAD="khazad";
	public static final String CIPHER_RIJNDAEL="rijndael";
	public static final String CIPHER_SERPENT="serpent";
	public static final String CIPHER_SQUARE="square";
	public static final String CIPHER_TRIPLEDES="tripledes";
	public static final String CIPHER_TWOFISH="twofish";
	public static final String HASH_HAVAL="haval";
	public static final String HASH_MD2="md2";
	public static final String HASH_MD4="md4";
	public static final String HASH_MD5="md5";
	public static final String HASH_RIPEMD128="ripemd128";
	public static final String HASH_SHA160="sha-160";
	public static final String HASH_SHA256="sha-256";
	public static final String HASH_SHA384="sha-384";
	public static final String HASH_SHA512="sha-512";
	public static final String HASH_TIGER="tiger";
	public static final String HASH_WHIRLPOOL="whirlpool";
	public static final String PAD_EME_PKCS1_v1_5="eme-pkcs1-v1.5";
	public static final String PAD_PKCS7="pkcs7";
	public static final String PAD_TBC="tbc";
	
	private static final String DEFAULT_CIPHER=CIPHER_SERPENT;
	private static final String DEFAULT_HASH=HASH_SHA256;
	private static final String DEFAULT_PAD=PAD_TBC;
	
	private CryptographyModule(){
	}
	
	public static byte[] encrypt(byte[] input, byte[] key) throws InvalidKeyException, IllegalStateException{
		return encrypt(input, key, DEFAULT_CIPHER, DEFAULT_HASH, DEFAULT_PAD);
	}
	
	public static byte[] encrypt(byte[] input, byte[] key, String cipherName, String hashName, String padName) throws InvalidKeyException, IllegalStateException{
		IBlockCipher iBlockCipher=CipherFactory.getInstance(cipherName);
		int blockSize=iBlockCipher.defaultBlockSize();
		Map<String, Object> attributes=new HashMap<String, Object>();
		attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, blockSize);
		attributes.put(IBlockCipher.KEY_MATERIAL, getHash(key, hashName));
		iBlockCipher.init(attributes);
		byte[] paddedInput=getPaddedData(input, padName, blockSize);
		byte[] output=new byte[paddedInput.length];
		for(int i=0;i<paddedInput.length/blockSize;i++){
			iBlockCipher.encryptBlock(paddedInput, i*blockSize, output, i*blockSize);
		}
		return output;
	}
	
	public static byte[] decrypt(byte[] input, byte[] key) throws InvalidKeyException, IllegalStateException, WrongPaddingException{
		return decrypt(input, key, DEFAULT_CIPHER, DEFAULT_HASH, DEFAULT_PAD);
	}
	
	public static byte[] decrypt(byte[] input, byte[] key, String cipherName, String hashName, String padName) throws InvalidKeyException, IllegalStateException, WrongPaddingException{
		IBlockCipher iBlockCipher=CipherFactory.getInstance(cipherName);
		int blockSize=iBlockCipher.defaultBlockSize();
		Map<String, Object> attributes=new HashMap<String, Object>();
		attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, blockSize);
		attributes.put(IBlockCipher.KEY_MATERIAL, getHash(key, hashName));
		iBlockCipher.init(attributes);
		byte[] tempData=new byte[input.length];
		for(int i=0;i<input.length/blockSize;i++){
			iBlockCipher.decryptBlock(input, i*blockSize, tempData, i*blockSize);
		}
		return getUnpaddedData(tempData, padName, blockSize);
	}
	
	public static byte[] getHash(byte[] input, String hashName){
		IMessageDigest iMessageDigest=HashFactory.getInstance(hashName);
		iMessageDigest.update(input, 0, input.length);
		return iMessageDigest.digest();
	}
	
	public static byte[] getPaddedData(byte[] input, String padName, int blockSize){
		IPad iPad=PadFactory.getInstance(padName);
		iPad.init(blockSize);
		byte[] padSequence=iPad.pad(input, 0, input.length);
		byte[] output=new byte[input.length+padSequence.length];
		System.arraycopy(input, 0, output, 0, input.length);
		System.arraycopy(padSequence, 0, output, input.length, padSequence.length);
		return output;
	}
	
	public static byte[] getUnpaddedData(byte[] input, String padName, int blockSize) throws WrongPaddingException{
		IPad iPad=PadFactory.getInstance(padName);
		iPad.init(blockSize);
		int remove=iPad.unpad(input, 0, input.length);
		byte[] output=new byte[input.length-remove];
		System.arraycopy(input, 0, output, 0, output.length);
		return output;
	}
	
	public static boolean compareHashes(byte[] input1, byte[] input2){
		if(input1.length!=input2.length){
			return false;
		}
		else{
			for(int i=0;i<input1.length;i++){
				if(input1[i]!=input2[i]){
					return false;
				}
			}
		}
		return true;
	}
	
}
 
Ich habe jetzt noch zusätzlich 4 Methoden mit Streams als Input und Output hinzugefügt, da ich das vor allem bei Dateiverschlüsselung als etwas schöner empfinde (außerdem gibts Probleme wenn man ein großes File in ein byte[] laden will).

Java:
import gnu.crypto.cipher.CipherFactory;
import gnu.crypto.cipher.IBlockCipher;
import gnu.crypto.hash.HashFactory;
import gnu.crypto.hash.IMessageDigest;
import gnu.crypto.pad.IPad;
import gnu.crypto.pad.PadFactory;
import gnu.crypto.pad.WrongPaddingException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.util.HashMap;
import java.util.Map;

public class CryptographyModule{
	
	public static final String CIPHER_ANUBIS="anubis";
	public static final String CIPHER_BLOWFISH="blowfish";
	public static final String CIPHER_CAST5="cast5";
	public static final String CIPHER_DES="des";
	public static final String CIPHER_KHAZAD="khazad";
	public static final String CIPHER_RIJNDAEL="rijndael";
	public static final String CIPHER_SERPENT="serpent";
	public static final String CIPHER_SQUARE="square";
	public static final String CIPHER_TRIPLEDES="tripledes";
	public static final String CIPHER_TWOFISH="twofish";
	public static final String HASH_HAVAL="haval";
	public static final String HASH_MD2="md2";
	public static final String HASH_MD4="md4";
	public static final String HASH_MD5="md5";
	public static final String HASH_RIPEMD128="ripemd128";
	public static final String HASH_SHA160="sha-160";
	public static final String HASH_SHA256="sha-256";
	public static final String HASH_SHA384="sha-384";
	public static final String HASH_SHA512="sha-512";
	public static final String HASH_TIGER="tiger";
	public static final String HASH_WHIRLPOOL="whirlpool";
	public static final String PAD_EME_PKCS1_v1_5="eme-pkcs1-v1.5";
	public static final String PAD_PKCS7="pkcs7";
	public static final String PAD_TBC="tbc";
	
	private static final String DEFAULT_CIPHER=CIPHER_SERPENT;
	private static final String DEFAULT_HASH=HASH_SHA256;
	private static final String DEFAULT_PAD=PAD_TBC;
	private static final int DEFAULT_BUFFER_SIZE=1024;
	
	private CryptographyModule(){
	}
	
	public static byte[] encrypt(byte[] input, byte[] key) throws InvalidKeyException, IllegalStateException{
		return encrypt(input, key, DEFAULT_CIPHER, DEFAULT_HASH, DEFAULT_PAD);
	}
	
	public static void encrypt(InputStream inputStream, OutputStream outputStream, byte[] key) throws IOException, InvalidKeyException, IllegalStateException{
		encrypt(inputStream, outputStream, key, DEFAULT_BUFFER_SIZE, DEFAULT_CIPHER, DEFAULT_HASH, DEFAULT_PAD);
	}
	
	public static void encrypt(InputStream inputStream, OutputStream outputStream, byte[] key, int bufferSize, String cipherName, String hashName, String padName) throws InvalidKeyException, IllegalStateException, IOException{
		int read;
		byte[] buffer=new byte[bufferSize];
		while((read=inputStream.read(buffer))!=-1){
			byte[] temp=new byte[read];
			System.arraycopy(buffer, 0, temp, 0, read);
			outputStream.write(encrypt(temp, key));
		}
	}
	
	public static byte[] encrypt(byte[] input, byte[] key, String cipherName, String hashName, String padName) throws InvalidKeyException, IllegalStateException{
		IBlockCipher iBlockCipher=CipherFactory.getInstance(cipherName);
		int blockSize=iBlockCipher.defaultBlockSize();
		Map<String, Object> attributes=new HashMap<String, Object>();
		attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, blockSize);
		attributes.put(IBlockCipher.KEY_MATERIAL, getHash(key, hashName));
		iBlockCipher.init(attributes);
		byte[] paddedInput=getPaddedData(input, padName, blockSize);
		byte[] output=new byte[paddedInput.length];
		for(int i=0;i<paddedInput.length/blockSize;i++){
			iBlockCipher.encryptBlock(paddedInput, i*blockSize, output, i*blockSize);
		}
		return output;
	}
	
	public static byte[] decrypt(byte[] input, byte[] key) throws InvalidKeyException, IllegalStateException, WrongPaddingException{
		return decrypt(input, key, DEFAULT_CIPHER, DEFAULT_HASH, DEFAULT_PAD);
	}
	
	public static void decrypt(InputStream inputStream, OutputStream outputStream, byte[] key) throws IOException, InvalidKeyException, IllegalStateException, WrongPaddingException{
		decrypt(inputStream, outputStream, key, DEFAULT_BUFFER_SIZE, DEFAULT_CIPHER, DEFAULT_HASH, DEFAULT_PAD);
	}
	
	public static void decrypt(InputStream inputStream, OutputStream outputStream, byte[] key, int bufferSize, String cipherName, String hashName, String padName) throws InvalidKeyException, IllegalStateException, IOException, WrongPaddingException{
		int read;
		byte[] buffer=new byte[bufferSize];
		while((read=inputStream.read(buffer))!=-1){
			byte[] temp=new byte[read];
			System.arraycopy(buffer, 0, temp, 0, read);
			outputStream.write(decrypt(temp, key));
		}
	}
	
	public static byte[] decrypt(byte[] input, byte[] key, String cipherName, String hashName, String padName) throws InvalidKeyException, IllegalStateException, WrongPaddingException{
		IBlockCipher iBlockCipher=CipherFactory.getInstance(cipherName);
		int blockSize=iBlockCipher.defaultBlockSize();
		Map<String, Object> attributes=new HashMap<String, Object>();
		attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, blockSize);
		attributes.put(IBlockCipher.KEY_MATERIAL, getHash(key, hashName));
		iBlockCipher.init(attributes);
		byte[] tempData=new byte[input.length];
		for(int i=0;i<input.length/blockSize;i++){
			iBlockCipher.decryptBlock(input, i*blockSize, tempData, i*blockSize);
		}
		return getUnpaddedData(tempData, padName, blockSize);
	}
	
	public static byte[] getHash(byte[] input, String hashName){
		IMessageDigest iMessageDigest=HashFactory.getInstance(hashName);
		iMessageDigest.update(input, 0, input.length);
		return iMessageDigest.digest();
	}
	
	public static byte[] getPaddedData(byte[] input, String padName, int blockSize){
		IPad iPad=PadFactory.getInstance(padName);
		iPad.init(blockSize);
		byte[] padSequence=iPad.pad(input, 0, input.length);
		byte[] output=new byte[input.length+padSequence.length];
		System.arraycopy(input, 0, output, 0, input.length);
		System.arraycopy(padSequence, 0, output, input.length, padSequence.length);
		return output;
	}
	
	public static byte[] getUnpaddedData(byte[] input, String padName, int blockSize) throws WrongPaddingException{
		IPad iPad=PadFactory.getInstance(padName);
		iPad.init(blockSize);
		int remove=iPad.unpad(input, 0, input.length);
		byte[] output=new byte[input.length-remove];
		System.arraycopy(input, 0, output, 0, output.length);
		return output;
	}
	
	public static boolean compareHashes(byte[] input1, byte[] input2){
		if(input1.length!=input2.length){
			return false;
		}
		else{
			for(int i=0;i<input1.length;i++){
				if(input1[i]!=input2[i]){
					return false;
				}
			}
		}
		return true;
	}
	
}
 

Zurück
Oben