Bertold wrote:
Hi,
I am trying to use password based encryption, and got a code working. My problem is that if I feed the same parameters (password, salt, iteration count) into an equivalent code written in Java (and using Sun JRE 1.4.2), then the result of the encryption will be different.
I could not quite figure out why there is a difference.
Below you can find the Java code using the standard JCE shipped with Java 1.4, and the code using NSS.
As an exampe, here is the result of encrypting the string "test" with the 2 different implementations.
$ ./pbe test calling encrypt: 0x36 0xb5 0xc5 0x39 0x5c 0x72 0x71 0x26
$ java -cp . PBE test calling encrypt(): 0xca 0xa6 0x8f 0xb3 0x77 0x36 0xe9 0x8a
I would appreciate any help.
Thanks,
Bertold
My first suspicion would be one or the other is converting the password to Unicode before using it.
bob
PBE.cpp: -------- #include "PBE.hpp" #include <nss.h> #include <stdio.h>
const unsigned char * const PBE::_pbeRawPassword = (unsigned char *)"testPassword"; const int PBE::_pbeRawPasswordLength = 12; const SECItem PBE::_pbePassword = { siClearDataBuffer, (unsigned char *)_pbeRawPassword, _pbeRawPasswordLength };
const unsigned char PBE::_pbeRawSalt[] = { 1,2,3,4,5,6,7,8 }; const SECItem PBE::_pbeSalt = { siClearDataBuffer, (unsigned char *)_pbeRawSalt, 8 /* salt length */};
const int PBE::_iterationCount = 1000;
PBE::PBE(const unsigned char * const data, int len) : _data(NULL), _slot(NULL)
{ _data = data; _len = len; _slot = PK11_GetInternalSlot(); }
void PBE::encrypt() { unsigned char paddedData[4096]; int paddedDataLen; unsigned char encryptedData[4096]; int encryptedDataLen; PK11Context * context; SECAlgorithmID * pbeSecAlgorithmId = PK11_CreatePBEAlgorithmID(SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC, _iterationCount, (SECItem *)&_pbeSalt);
PK11SymKey * pbeKey = PK11_PBEKeyGen(_slot, pbeSecAlgorithmId, (SECItem *)&_pbePassword, PR_FALSE, NULL);
context = PK11_CreateContextBySymKey(CKM_DES_CBC, CKA_ENCRYPT, pbeKey, (SECItem *)&_pbeSalt);
addPadding(_data, _len, paddedData, &paddedDataLen);
PK11_CipherOp(context, encryptedData, &encryptedDataLen, paddedDataLen, // maximum data length paddedData, paddedDataLen);
PK11_Finalize(context);
PK11_DestroyContext(context, PR_TRUE);
printByteArray(encryptedData, encryptedDataLen); }
void PBE::addPadding(const unsigned char * const src, int srcLen, unsigned char * dst, int * dstLen) { int i = 0; unsigned char padChar = 8 - (srcLen % 8); memmove((void *)dst, src, srcLen); for (i=0; i<padChar; i++) { dst[srcLen + i] = padChar; } *dstLen = srcLen + padChar; }
void PBE::printByteArray(const unsigned char * const data, int len) { int i = 0; char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
for (i=0; i<len; i++) { unsigned char c = data[i]; printf(" 0x%c%c", hexChars[c >> 4], hexChars[c & 0x0f]); } printf("\n"); }
int main(int argc, char *argv[]) { PBE * p = NULL; if (argc != 2) { fprintf(stderr, "usage: pbe <password to encrypt>\n"); return -1; }
NSS_NoDB_Init("/tmp");
p = new PBE((unsigned char *)argv[1], strlen(argv[1])); printf("calling encrypt: "); p->encrypt();
return 0; }
PBE.hpp: -------- #include <pk11func.h>
class PBE { public: PBE(const unsigned char * const data, int len); virtual void encrypt();
private: static void printByteArray(const unsigned char * const data, int len); static void addPadding(const unsigned char * const src, int srcLen, unsigned char * dst, int * dstLen); const unsigned char * _data; int _len; PK11SlotInfo * _slot;
static const unsigned char * const _pbeRawPassword; static const int _pbeRawPasswordLength; static const SECItem _pbePassword; static const unsigned char _pbeRawSalt[8]; static const SECItem _pbeSalt; static const int _iterationCount;
PBE(const PBE& string); PBE& operator=(const PBE& string); };
PBE.java: --------- import javax.crypto.Cipher; import javax.crypto.SecretKeyFactory; import javax.crypto.SecretKey; import javax.crypto.spec.PBEParameterSpec; import javax.crypto.spec.PBEKeySpec; import java.security.spec.KeySpec; import java.security.spec.AlgorithmParameterSpec;
public class PBE { private static final char[] password = "testPassword".toCharArray(); private static final byte[] salt = { 1, 2, 3, 4, 5, 6, 7, 8 }; private static final int iterationCount = 1000; private static final String algorithm = "PBEWithMD5AndDES";
private byte[] _data = null;
public PBE(String data) { _data = data.getBytes(); }
public void encrypt() throws Exception { Cipher cipher = Cipher.getInstance(algorithm); SecretKeyFactory factory = SecretKeyFactory.getInstance(algorithm); // create keyspec without passing in salt and iteration count KeySpec keySpec = new PBEKeySpec(password); SecretKey key = factory.generateSecret(keySpec);
// create algorithm parameters using the salt and the iteration count AlgorithmParameterSpec pbeParams = new PBEParameterSpec(salt, iterationCount);
// initialize cipher with key and algorithm parameters cipher.init(Cipher.ENCRYPT_MODE, key, pbeParams); printByteArray(cipher.doFinal(_data)); }
public static void printByteArray(byte[] data) { final char[] hexChars = "0123456789abcdef".toCharArray();
for (int i=0; i<data.length; i++) { int b = data[i]; if (b < 0) { b = 256 + b; } System.out.print(" 0x"); System.out.print(hexChars[b >> 4]); System.out.print(hexChars[0x0f & b]); } System.out.println(); }
public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("usage: PBE <string to encrypt>"); } PBE p = new PBE(args[0]); System.out.print("calling encrypt(): "); p.encrypt(); } }
_______________________________________________
mozilla-crypto mailing list
[email protected]
http://mail.mozilla.org/listinfo/mozilla-crypto
smime.p7s
Description: S/MIME Cryptographic Signature
