I found this code on a forum:
Public Shared Sub Encryptor(wme As String, password As String)
Try
Dim key As Byte() = New Byte(31) {}
Encoding.Default.GetBytes(password).CopyTo(key, 0)
Dim aes As New RijndaelManaged() With
{
.Mode = CipherMode.CBC,
.KeySize = 256,
.BlockSize = 256,
.Padding = PaddingMode.Zeros
}
Dim buffer As Byte() = File.ReadAllBytes(wme)
Using matrizStream As New MemoryStream
Using cStream As New CryptoStream(matrizStream, aes.CreateEncryptor(key, key), CryptoStreamMode.Write)
cStream.Write(buffer, 0, buffer.Length)
Dim appendBuffer As Byte() = matrizStream.ToArray()
Dim finalBuffer As Byte() = New Byte(appendBuffer.Length - 1) {}
appendBuffer.CopyTo(finalBuffer, 0)
File.WriteAllBytes(wme, finalBuffer)
End Using
End Using
File.Move(wme, wme)
Catch
End Try
End Sub
wme is the file path. Password is the password for the encryption. I was woundering if this was a strong encryption method or its some bad encryption method.
Rijndael with a BlockSize of 256-bits is not AES, AES only supports a block size if 128-bits. Not 31 bytes, there would be some unknown padding applied.
For AES use: .BlockSize = 128.
You need to supply an Initialization Vector (IV). The IV will also be the same as the block size, 128-bits (16-bytes), make it exactly that size. Use a random IV and prefix the encrypted data with it so it will be available for decryption.
Also AES supports three key sizes, 128, 192 and 256 bits, make the keys exactly the correct size.
Further, null padding is a bad idea and does not support binary data, instead the usual padding is PKCS#7 (sometimes specified as PKCS#5).
Related
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?
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), ...
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;
}
When I try to make ECC private key from byte array, I get exception mentioned below. I have public/private keys and out signed output from C library micro-ecc/uECC.h. C used secp192r1 curve. I am trying to verify data with C generated keys in Java. How to convert byte array to private/public key?
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
byte[] kb = 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};
X509EncodedKeySpec ks = new X509EncodedKeySpec(kb);
KeyFactory kf = java.security.KeyFactory.getInstance("ECDH", "BC");
org.bouncycastle.jce.interfaces.ECPrivateKey remotePublicKey = (org.bouncycastle.jce.interfaces.ECPrivateKey)kf.generatePublic(ks);
java.security.spec.InvalidKeySpecException: encoded key spec not recognised
at org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi.engineGeneratePublic(Unknown Source)
at org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi.engineGeneratePublic(Unknown Source)
at java.security.KeyFactory.generatePublic(KeyFactory.java:328)
Also I have tried to use
KeyFactory.getInstance("ECDH", "BC");
but it throws the same exception above.
KeyFactory.getInstance("EC");
throws
java.security.InvalidKeyException: invalid key format
or
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : DerInputStream.getLength(): lengthTag=116, too big.
X509EncodedKeySpec(key) or PKCS8EncodedKeySpec(key) constructors take private/public keys in encoded format. Unencoded key bytes can be converted this way:
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));
I'm implementing a webservice client that is required to encrypt the request using 128-bits Rijndael. Because the RijndaelManaged class doesn't exist in Silverlight, I've followed the advice here:
This was discussed here: AesManaged and RijndaelManaged
The result is that the result I'm getting is correct (I mean, the same I'm getting using RijndaelManaged) only for the first 32 characters (128 bits), exactly the block size. I can't figure out what I'm doing wrong here. My .Net implementation (RijndaelManaged) goes like this:
private static byte[] Encrypt(byte[] PlainTextBytes, byte[] KeyBytes, string InitialVector)
{
byte[] InitialVectorBytes = Encoding.UTF8.GetBytes(InitialVector);
RijndaelManaged SymmetricKey = new RijndaelManaged();
SymmetricKey.Mode = CipherMode.ECB;
SymmetricKey.Padding = PaddingMode.PKCS7;
SymmetricKey.BlockSize = 128;
ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes);
MemoryStream MemStream = new MemoryStream();
CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);
CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
CryptoStream.FlushFinalBlock();
byte[] CipherTextBytes = MemStream.ToArray();
MemStream.Close();
CryptoStream.Close();
return CipherTextBytes;
}
while my Silverlight is:
private string Encrypt(byte[] PlainTextBytes, byte[] KeyBytes, string InitialVector)
{
AesManaged SymmetricKey = new AesManaged();
byte[] InitialVectorBytes = SymmetricKey.IV;
//NOTE- because Mode and Padding don't exist in AESManaged for Silverlight, I have to do the padding myself
//for an empty InitalVector (which is my case)
for (int i = 0; i < InitialVectorBytes.Length; i++) InitialVectorBytes[i] = 0;
SymmetricKey.BlockSize = 128;
ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes);
MemoryStream MemStream = new MemoryStream();
CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);
CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
CryptoStream.FlushFinalBlock();
byte[] CipherTextBytes = MemStream.ToArray();
MemStream.Close();
CryptoStream.Close();
return CipherTextBytes;
}
It's not clear that you're really clearing the IV. You're fetching it as a byte array and then clearing that, but I don't know for sure whether the IV property copies the internal value before returning it. I'd use this:
SymmetricKey.BlockSize = 128;
SymmetricKey.IV = new byte[SymmetricKey.BlockSize / 8];
(I'd also stop using PascalCase for parameters and local variables, by the way. The normal convention is to use camelCase for non-constant variables.)
EDIT: Sample code to demonstrate how your code isn't really changing the IV:
AesManaged aes = new AesManaged();
byte[] iv = aes.IV;
iv[0] = 1;
iv[1] = 2;
Console.WriteLine(BitConverter.ToString(iv));
Console.WriteLine(BitConverter.ToString(aes.IV));
Sample output:
01-02-01-1B-6E-05-B8-2A-C0-86-17-EF-A2-80-60-7B
D8-48-01-1B-6E-05-B8-2A-C0-86-17-EF-A2-80-60-7B
In other words, changing the values in the array isn't changing the IV really.
Your .NET version uses EBC mode for AES while the Silverlight version uses CBC. The first output block is the same in both versions because in ECB mode the initialization vector is not used and in CBC mode the initialization vector is zero. In CBC mode each block is XORed with the previous block (first block is XORed with the initialization vector) and then encrypted while in EBC mode each block is encrypted as it is.