Thingol
Conforme vc me informou, a chave do 3DES é de 21 bytes. Adicionando os bits de paridade fica com 24 bytes.
Implementei o metodo que adiciona os bits de paridade e ainda estou com os resultados diferentes no Java dos obtidos no C.
Será que vc tem mais alguma idéia?
Segue abaixo o código completo em Java e em C.
A senha utilizada é “test password” e os dados criptorafados são “The book is on the table”
Estou passando o IV zerado.
package foo.bar.cripto;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Crypto {
public static final int HASH_TYPE_MD5 = 1;
public static final int HASH_TYPE_SHA1 = 2;
public byte[] calcHash(byte[] data, int algorithmType) throws NoSuchAlgorithmException {
MessageDigest md = null;
if (HASH_TYPE_MD5 == algorithmType)
md = MessageDigest.getInstance("MD5");
else if (HASH_TYPE_SHA1 == algorithmType)
md = MessageDigest.getInstance("SHA-1");
else
throw new NoSuchAlgorithmException();
md.update(data);
byte bufferSaida[] = md.digest();
return bufferSaida;
}
public byte[] crypt(String data, String key, int algorithmType) throws Exception {
byte[] hashKey = null;
Cipher cipher = null;
int keySize = 21; // 3DES key size
hashKey = calcHash(key.getBytes(), HASH_TYPE_SHA1);
byte[] derivedKey = addParityBit(cryptDeriveKey(hashKey, keySize, HASH_TYPE_SHA1));
byte[] iv = new byte[8];
Arrays.fill(iv, (byte)0x00);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
SecretKeySpec secretKeySpec = new SecretKeySpec(derivedKey, "DESede");
cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] cryptData = cipher.doFinal(data.getBytes());
return cryptData;
}
private byte[] cryptDeriveKey(byte[] key, int size, int algorithmType) throws Exception {
byte[] buffer1 = new byte[64];
byte[] buffer2 = new byte[64];
// Preenche os buffers
Arrays.fill(buffer1, (byte) 0x36);
Arrays.fill(buffer2, (byte) 0x5C);
// Faz o XOR da chave com os buffers
for (int i = 0; i < key.length; i++) {
buffer1[i] ^= key[i];
buffer2[i] ^= key[i];
}
// Calcula o hash utilizando o mesmo algoritmo utilizado na chave passada
try {
buffer1 = calcHash(buffer1, algorithmType);
buffer2 = calcHash(buffer2, algorithmType);
} catch (NoSuchAlgorithmException e) {
throw new Exception(e);
}
// Transporta os bytes dos buffers para a chave final até o tamanho desejado
byte[] derivedKey = new byte[size];
for (int i = 0; i < size; i++) {
if (i < buffer1.length)
derivedKey[i] = buffer1[i];
else
derivedKey[i] = buffer2[i - buffer1.length];
}
return derivedKey;
}
private byte[] addParityBit(byte[] key) throws Exception {
if (key.length % 7 != 0)
throw new Exception("Invalid data length");
byte[] keyData = new byte[key.length + key.length / 7];
byte b, deslocamento = 0, sobra = 0, j = 0;
for (short i = 0; i < key.length; i++) {
// Adiciona a sobra anterior no início do próximo byte
b = (byte) ((sobra << 8 - deslocamento) | ((key[i] & 0xFF) >> deslocamento));
// Obtém a nova sobra
sobra = (byte) (key[i] & (0x0FF >> (7 - deslocamento++)));
// Adiciona o bit de paridade na saída
keyData[i + j] = addParityBit(b);
// Calcula o oitavo byte em cima da sobra do setimo byte
if ((i + 1) % 7 == 0) {
keyData[i + ++j] = addParityBit((byte) (sobra << 1));
sobra = 0;
deslocamento = 0;
}
}
return keyData;
}
private byte addParityBit(byte b) {
byte paridade = (byte) ((b >> 1) ^ (b >> 2) ^ (b >> 3) ^ (b >> 4) ^ (b >> 5) ^ (b >> 6) ^ (b >> 7));
return (byte) ((b & 0xFE) | (paridade & 0x01));
}
private void showBinary(byte value) {
StringBuffer sb = new StringBuffer();
for (int i = 7; i >= 0; i--)
sb.append((value >> i) & 0x01);
System.out.println(sb.toString());
}
}
======================================
Segue o código de teste em C
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <windows.h>
#include <wincrypt.h>
void crypt();
void MyHandleError(char *s);
int main() {
crypt();
return 0;
}
void crypt() {
HCRYPTPROV hCryptProv;
HCRYPTKEY hKey;
HCRYPTHASH hHash;
CHAR szPassword[14] = "test password";
CHAR szDataIn[25] = "The book is on the table";
DWORD dwPassLen = strlen(szPassword);
DWORD dwDataInLen = strlen(szDataIn);
//--------------------------------------------------------------------
// Acquire a cryptographic provider context handle.
if(!CryptAcquireContext(&hCryptProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
MyHandleError("Error during CryptAcquireContext!");
}
//--------------------------------------------------------------------
// Create an empty hash object.
if(!CryptCreateHash(hCryptProv, CALG_SHA1, 0, 0, &hHash)) {
MyHandleError("Error during CryptCreateHash!");
}
//--------------------------------------------------------------------
// Hash the password string.
if(!CryptHashData(hHash, (BYTE *)szPassword, dwPassLen, 0)) {
MyHandleError("Error during CryptHashData!");
}
/*DWORD tamHash2 = 0;
if(!CryptGetHashParam(hHash, HP_HASHVAL, NULL, &tamHash2, 0)) {
MyHandleError("Bla bla");
}
BYTE * pbHash2 = new BYTE[tamHash2 + 1];
memset(pbHash2, 0, tamHash2 + 1);
if(!CryptGetHashParam(hHash, HP_HASHVAL, pbHash2, &tamHash2, 0)) {
MyHandleError("Bla bla");
}*/
//--------------------------------------------------------------------
// Create a session key based on the hash of the password.
if(!CryptDeriveKey(hCryptProv, CALG_3DES, hHash, CRYPT_EXPORTABLE, &hKey)) {
MyHandleError("Error during CryptDeriveKey!");
}
DWORD dwDataOutLen = dwDataInLen;
if(!CryptEncrypt(hKey, 0, TRUE, 0, NULL, &dwDataOutLen, dwDataOutLen)) {
MyHandleError("Error during CryptEncrypt!");
}
BYTE * szDataOut = new BYTE[dwDataOutLen + 1];
memset(szDataOut, 0, dwDataOutLen + 1);
if(!CryptEncrypt(hKey, 0, TRUE, 0, szDataOut, &dwDataInLen, dwDataOutLen)) {
MyHandleError("Error during CryptEncrypt!");
}
// Destroy the hash object.
if(hHash) {
if(!(CryptDestroyHash(hHash)))
MyHandleError("Error during CryptDestroyHash");
}
// Destroy the session key.
if(hKey) {
if(!(CryptDestroyKey(hKey)))
MyHandleError("Error during CryptDestroyKey");
}
// Release the provider handle.
if(hCryptProv) {
if(!(CryptReleaseContext(hCryptProv, 0)))
MyHandleError("Error during CryptReleaseContext");
}
printf("The program to derive a key completed without error. \n");
}
void MyHandleError(char *s) {
printf("An error occurred in running the program.\n");
printf("%s\n",s);
printf("Error number %x\n.",GetLastError());
printf("Program terminating.\n");
exit(1);
}