SalesForce marketing System not getting decrypted in Using java Crypto - salesforce-communities

I need some help in understanding, how to decrypt SalesforceMarketingCloud encrypted String into java.
I should admit that I have few things missing in my questions but this is what ever I have been provided so far
Algorithm – AES256, 256 Bit
Initilization vector – 16 bytes
Salt – 8 Bytes
Passphrase – “presharedpassphrase123”
As per my understanding the Input String has been encrypted using
EncryptSymmetric(#Clear, "AES", #null, #Passphrase, #null, #Salt, #null, #IV)
But when I try to decrypt it at Java side, it fails for various reason.
My best shot has been getting a garbage String as output so far when I used combination like below
NoPadding, CBS, and hashing my passphrase(which is 22 char long) to 32 bit using SHA-256
Can anyone please help, any Java code sample which you successfully used in past.
private String decryptWithKey(String myKey, byte[] strToDecrypt) throws Exception
{
MessageDigest sha = null;
try {
key = myKey.getBytes(CHAR_SCHEME);
sha = MessageDigest.getInstance("SHA-256");
key = sha.digest(key);
key = Arrays.copyOf(key, 32);
secretKey = new SecretKeySpec(key, ALGO);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
byte[] ivByte = new byte[cipher.getBlockSize()];
ivByte = hexStringToByteArray("0716A494177F29F102AF33AFD0253BA1");;
System.out.println(new String(ivByte));
// IvParameterSpec ivParamsSpec = new IvParameterSpec(IV);
IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParamsSpec);
setDecryptedString(new String(cipher.doFinal(strToDecrypt)));
}
catch (Exception e)
{
System.out.println("Error while decrypting: "+e.toString());
throw e;
}
return decryptedString;
}

Related

AES-GCM decryption error iaik.cms.CMSException: Unable to decrypt encrypted content-encryption key: Invalid padding

I am using following code to encrypt data using AES-GCM:
// the stream to which to write the EnvelopedData
ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
EnvelopedDataOutputStream envelopedData;
// wrap EnvelopedData into a ContentInfo
ContentInfoOutputStream contentInfoStream =
new ContentInfoOutputStream(ObjectID.cms_envelopedData, resultStream);
// create a new EnvelopedData object encrypted with AES
try {
envelopedData = new EnvelopedDataOutputStream(contentInfoStream,
(AlgorithmID)AlgorithmID.aes256_GCM.clone());
} catch (NoSuchAlgorithmException ex) {
throw new CMSException("No implementation for AES.");
}
// create the recipient infos
RecipientInfo[] recipients = new RecipientInfo[1];
// user1 is the first receiver
recipients[0] = new KeyTransRecipientInfo(signCert,
(AlgorithmID)AlgorithmID.rsaEncryption.clone());
// specify the recipients of the encrypted message
envelopedData.setRecipientInfos(recipients);
//int blockSize = 2048; // in real world we would use a block size like 2048
// write in the data to be encrypted
//byte[] buffer = new byte[blockSize];
byte[] buffer = new byte[16];
//byte[] buffer;
int bytesRead;
while ((bytesRead = inputstream.read(buffer)) != -1) {
envelopedData.write(buffer, 0, bytesRead);
}
But while trying to decrypt the same using following code:
EnvelopedDataStream enveloped_data = new EnvelopedDataStream(is);
enveloped_data.setupCipher(privateSignKey, 0);
InputStream decrypted = enveloped_data.getInputStream();
ByteArrayOutputStream os = new ByteArrayOutputStream();
ByteStreams.copy(decrypted, os);
os.close();
I am getting following error:
iaik.cms.CMSException: Unable to decrypt encrypted content-encryption key: Invalid padding!
I am not sure of block size to be used, this might be a reason for the error, but not sure.
Moreover, if I compare my encrypted file with that of a correct one, I see following difference:
My encrypted data:
OBJECT IDENTIFIER 2.16.840.1.101.3.4.1.46 aes256-GCM (NIST Algorithm)
SEQUENCE (1 elem)
OCTET STRING (12 byte) FE5729470184A04A5AA30158
Correct data:
OBJECT IDENTIFIER 2.16.840.1.101.3.4.1.46 aes256-GCM (NIST Algorithm)
SEQUENCE (2 elem)
OCTET STRING (12 byte) CA985F7EAFB709DF711DCA2A
INTEGER 16
Could you please help us in getting this to work?

placing the separately signed hash to Multiple places in PDF using itextsharp

I want to place same externally signed hash (signature value) at multiple places in a PDF.
I have referred the page 'how-to-place-the-same-digital-signatures-to-multiple-places-in-pdf-using-itextsh' and tried to implement the work around provided by mkl (please refer this How to place the Same Digital signatures to Multiple places in PDF using itextsharp.net).
And it works. I ported it to get the signer bytes signed externally using web service/ api and it also works. Now due to one of the requirement I changed the way hash is being calculated.
now instead of (old one):
byte[] hash = DigestAlgorithms.Digest(data, "SHA256");
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
I am trying to use (new one):
int contentEstimated=8192;
HashAlgorithm sha = new SHA256CryptoServiceProvider();
int read = 0;
byte[] buff = new byte[contentEstimated];
while ((read = data.Read(buff, 0, contentEstimated)) > 0)
{
sha.TransformBlock(buff, 0, read, buff, 0);
}
sha.TransformFinalBlock(buff, 0, 0);
byte[] hash = Org.BouncyCastle.Utilities.Encoders.Hex.Encode(sha.Hash);
string hashtext = Encoding.UTF8.GetString(hash, 0, hash.Length); //for writing it to file or sharing it to another api
byte[] hash1 = StringToByteArray(hashtext);
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash1, null, null, CryptoStandard.CMS); or
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS); //tried both
and if I try to use it in existing implementation, the signature gets invalid with an error "Document has been altered or corrupt since it was signed". Can you please tell me where I am doing it wrong?
At most of the referred pages, they have used this hash generation method with an embed function where the calculated hash is getting embedded in the pdf,
byte[] paddedSig = new byte[csize];
System.Array.Copy(pk, 0, paddedSig, 0, pk.Length);
PdfDictionary dic2 = new PdfDictionary();
dic2.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true));
appearance.Close(dic2);
Thank you.
- Tanmay
In comments the OP clarified that he wants to adapt the solution here to using an external signing service which accepts a document hash (more exactly a SHA256 hash value of the document in Hex format) and returns a full-fledged CMS signature container.
In this case the original AllPagesSignatureContainer method Sign
public byte[] Sign(Stream data)
{
String hashAlgorithm = externalSignature.GetHashAlgorithm();
PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, false);
IDigest messageDigest = DigestUtilities.GetDigest(hashAlgorithm);
byte[] hash = DigestAlgorithms.Digest(data, hashAlgorithm);
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
byte[] extSignature = externalSignature.Sign(sh);
sgn.SetExternalDigest(extSignature, null, externalSignature.GetEncryptionAlgorithm());
return sgn.GetEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);
}
has to be changed to not itself create a CMS container using the PdfPKCS7 sgn but merely calculate the document hash, send it to the service and use the container returned by the service:
public byte[] Sign(Stream data)
{
String hashAlgorithm = externalSignature.GetHashAlgorithm();
IDigest messageDigest = DigestUtilities.GetDigest(hashAlgorithm);
byte[] hash = DigestAlgorithms.Digest(data, hashAlgorithm);
byte[] hexHash = Org.BouncyCastle.Utilities.Encoders.Hex.Encode(hash);
string hexHashString = Encoding.UTF8.GetString(hexHash , 0, hexHash.Length);
var response = [... call service with document hash hexHashString ...];
byte[] signatureContainer = [... extract binary CMS container from response ...];
return signatureContainer;
}
The OP has not mentioned anything about the response format, so I cannot say more about the extract binary CMS container from response part. It may include selecting one attribute of a larger response structure, it may include decoding an encoded value (probably a Hex encoded string), ...

TLS 1.2 ECDHE_RSA signature

I'm currently working on a Java TLS server. I'm trying to get the following CipherSuite to work : TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
When I test it using openssl s_client I get the following error after the ServerKeyExchange message :
140735242416208:error:1414D172:SSL
routines:tls12_check_peer_sigalg:wrong signature type:t1_lib.c:1130:
Here is the TLS message as seen in Wireshark
The Handshake fails on a decode_error fatal error.
So I guess the client doesn't like the signature algorithm chosen.
But I am only using the default SignatureAndHashAlgorithm for now as per RFC 5246 Section-7.4.1.4.1
If the negotiated key exchange algorithm is one of (RSA, DHE_RSA,
DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA), behave as if client had sent
the value {sha1,rsa}.
(I'm still checking if the client do offer theses default values though)
Since I'm doing ECDHE_RSA I believe I should hash and sign the serverECDHparams as per RFC 4492 Section 5.4 (First post here so only 2 links sorry :) )
ServerKeyExchange.signed_params.sha_hash
SHA(ClientHello.random + ServerHello.random +
ServerKeyExchange.params);
struct {
select (KeyExchangeAlgorithm) {
case ec_diffie_hellman:
ServerECDHParams params;
Signature signed_params;
};
} ServerKeyExchange;
And I should do this as per RFC 2246 Section 7.4.3
select (SignatureAlgorithm) {
case rsa:
digitally-signed struct {
opaque md5_hash[16];
opaque sha_hash[20];
};
} Signature;
md5_hash
MD5(ClientHello.random + ServerHello.random + ServerParams);
sha_hash
SHA(ClientHello.random + ServerHello.random + ServerParams);
My Java code regarding signing the serverParams :
private byte[] getSignedParams(ChannelBuffer params)
throws NoSuchAlgorithmException, DigestException,
SignatureException, InvalidKeyException {
byte[] signedParams = null;
ChannelBuffer signAlg = ChannelBuffers.buffer(2);
MessageDigest md5 = MessageDigest.getInstance("MD5");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
switch (session.cipherSuite.sign) {
case rsa:
signAlg.writeByte(2); // 2 for SHA1
sha.update(clientRandom);
sha.update(serverRandom);
sha.update(params.toByteBuffer());
md5.update(clientRandom);
md5.update(serverRandom);
md5.update(params.toByteBuffer());
signedParams = concat(md5.digest(), sha.digest());
break;
}
signAlg.writeByte(session.cipherSuite.sign.value); // for RSA he byte is one
ChannelBuffer signLength = ChannelBuffers.buffer(2);
signLength.writeShort(signedParams.length);
return concat(signAlg.array(),concat(signLength.array(),signedParams));
}
So my question is basically : Am I wrong about all this ? and if so, what am I doing wrong ?
Thank you for your time ! :)
It's me again, I seem to have fixed my particular problem 2 things I noted :
Regarding my Java code, the MessageDigest class only does hashing no signing so I now use the Signature class instead.
It seems I only need to sign using SHA1 in TLS1.2 I don't need to do MD5 at all.
The second item is what I should have found in the RFC but didn't (maybe it is written somewhere, I don't know) I think this could be useful for people even if they're not doing Java ;)
How my code looks now :
private byte[] getSignedParams(ChannelBuffer params)
throws NoSuchAlgorithmException, DigestException,
SignatureException, InvalidKeyException {
byte[] signedParams = null;
Signature signature = Signature.getInstance(selectedSignAndHash.toString());
ChannelBuffer signAlg = ChannelBuffers.buffer(2);
signAlg.writeByte(selectedSignAndHash.hash.value);
signature.initSign(privateKey);
signature.update(clientRandom);
signature.update(serverRandom);
signature.update(params.toByteBuffer());
signedParams = signature.sign();
signAlg.writeByte(session.cipherSuite.sign.value);
ChannelBuffer signLength = ChannelBuffers.buffer(2);
signLength.writeShort(signedParams.length);
return concat(signAlg.array(), concat(signLength.array(), signedParams));
}
The code is different because in between I added a function to choose the SignatureAndHashAlgorithm to use from the list the client provides. But you could modify this to only respond using SHA1withRSA as this seems to be the default HashAndSignatureAlgorithm.

ECC public and private keys setters

I need to test ECC verification with given public and private keys. I found methods for random keys generation but there are no setters for specific public/private keys. How to set public/private keys as byte array?
byte[] privateKeyBytes = new byte[]{(byte)0x24, (byte)0xF4, (byte)0x36, (byte)0x16, (byte)0xD0, (byte)0x96, (byte)0x12, (byte)0x63, (byte)0x90, (byte)0x2E, (byte)0x51, (byte)0xF6, (byte)0x87, (byte)0x55, (byte)0xAB, (byte)0xCB, (byte)0x5D, (byte)0xAC, (byte)0x56, (byte)0x1A, (byte)0xA5, (byte)0xFA, (byte)0x55, (byte)0xDB};
byte[] publicKeyBytes = new byte[]{(byte)0x71, (byte)0x0B, (byte)0xCD, (byte)0xF8, (byte)0xEE, (byte)0x7F, (byte)0x36, (byte)0x32, (byte)0xF4, (byte)0x3E, (byte)0x8B, (byte)0x20, (byte)0x54, (byte)0xF7, (byte)0x84, (byte)0x26, (byte)0x4E, (byte)0x96, (byte)0xD9, (byte)0xBA, (byte)0x0F, (byte)0x82, (byte)0x84, (byte)0x2D, (byte)0xC1, (byte)0x31, (byte)0xE0, (byte)0xBF, (byte)0x9F, (byte)0x60, (byte)0x5F, (byte)0xAE, (byte)0x3A, (byte)0xA1, (byte)0x43, (byte)0x50, (byte)0x88, (byte)0x87, (byte)0xFE, (byte)0x49, (byte)0x6C, (byte)0x1F, (byte)0xF6, (byte)0x82, (byte)0x73, (byte)0xD8, (byte)0x77, (byte)0x8F};
KeyPair pair = g.generateKeyPair();
PublicKey pubKey = pair.getPublic();
PrivateKey prikey = pair.getPrivate();
Public and Private Keys can't be set, because they should be generated.
According to this, you won't be able to set it.
Normally you are able to encode a message and put the public key into the encoding method. Mabye you have an "ImportParameters"-Function like in C#, where you can import a "Key" into the chosen algorithm like RSA.
Edit:
According to THIS answer, you can import like this.
I would suggest you generate the keys, store them using a serialisation as JSON or something, so you can import, deserialise and import them in the method again
Used for encoded keys:
private static PrivateKey generatePrivateKey(KeyFactory factory, byte[] content){
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
return factory.generatePrivate(privKeySpec);
}
private static PublicKey generatePublicKey(KeyFactory factory, byte[] content) {
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
return factory.generatePublic(pubKeySpec);
}
For unencoded:
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp192r1");
ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(new BigInteger(1, privateKeyBytes), spec);
ECNamedCurveSpec params = new ECNamedCurveSpec("secp192r1", spec.getCurve(), spec.getG(), spec.getN());
java.security.spec.ECPoint w = new java.security.spec.ECPoint(new BigInteger(1, Arrays.copyOfRange(publicKeyBytes, 0, 24)), new BigInteger(1, Arrays.copyOfRange(publicKeyBytes, 24, 48)));
PublicKey publicKey = factory.generatePublic(new java.security.spec.ECPublicKeySpec(w, params));

Why PBE generates same key with different salt and iteration count?

I am trying to test PBE encryption/decryption. I found that PBE generates same key with different salt and iteration count. Of course, the password used is same.
As what I understand, same password and different salt/iteration should get different keys.
Below is my test code:
import java.security.Key;
import java.security.SecureRandom;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
public class PBETest
{
public static void main(String[] args)
throws Exception
{
String algo = "PBEWithSHA1andDESede";
System.out.println("====== " + algo + " ======");
char[] password = "password".toCharArray();
SecureRandom rand = new SecureRandom();
byte[] salt = new byte[32];
rand.nextBytes(salt);
int iterationCount = rand.nextInt(2048);
//encryption key
PBEKeySpec encPBESpec = new PBEKeySpec(password, salt, iterationCount);
SecretKeyFactory encKeyFact = SecretKeyFactory.getInstance(algo);
Key encKey = encKeyFact.generateSecret(encPBESpec);
System.out.println("encryptioin iteration: " + iterationCount);
//decryption key
rand.nextBytes(salt);
iterationCount = rand.nextInt(2048);
PBEKeySpec decPBESpec = new PBEKeySpec(password, salt, iterationCount);
SecretKeyFactory decKeyFact = SecretKeyFactory.getInstance(algo);
Key decKey = decKeyFact.generateSecret(decPBESpec);
System.out.println("decryptioin iteration: " + iterationCount);
System.out.println("encryption key is same as decryption key? " + encKey.equals(decKey));
}
}
I am expecting the final output is a false.
Did I do anything wrong?
You got spectacularly lucky, and your random salts and iteration counts just happened to match. Go directly to Las Vegas. Now. ;)
I googled for PBEWithSHA1andDESede and tracked down this example: http://cryptofreek.org/2010/06/04/encrypting-and-decrypting-files-with-java wherein he specifies the key alone with new PBEKeySpec(password) and creates a separate PBEParameterSpec using the salt and iteration count which is then passed to Cipher.init().
So, no, you did nothing wrong, you just stopped before the salt and count got stuffed into the cipher.
If you use PBKDF2WithHmacSHA1 instead of PBEWithSHA1andDESede your assumption works as it supports salt. You just need to add a the keyLength parameter to PBEKeySpec:
String algo = "PBKDF2WithHmacSHA1";
...
PBEKeySpec decPBESpec = new PBEKeySpec( password, salt, iterationCount, 128 );
I have run a test and the result is: false.
However, note that for encryption and decryption to work properly you need to use the same salt and iteration count when generating the key.