Encrypting and Decrypting Office 2007 documents - encryption

I am trying to encrypt and decrypt 2007 office documents. I am using System.Security.Cryptographic namespace
I am using the following code
using System;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Text;
namespace CSEncryptDecrypt
{
class Class1
{
static void Main()
{
// Must be 64 bits, 8 bytes.
// Distribute this key to the user who will decrypt this file.
string sSecretKey;
// Get the Key for the file to Encrypt.
sSecretKey = GenerateKey();
// Encrypt the file.
EncryptionHelper.EncryptFile(#"XCD - FTW Proposal.docx",
#"Encrypted.txt",
sSecretKey);
// Decrypt the file.
EncryptionHelper.DecryptFile(#"Encrypted.txt",
#"OUTPUT\XCD - FTW Proposal.docx",
sSecretKey);
}
// Function to Generate a 64 bits Key.
static string GenerateKey()
{
// Create an instance of Symetric Algorithm. Key and IV is generated automatically.
DESCryptoServiceProvider desCrypto = (DESCryptoServiceProvider)DESCryptoServiceProvider.Create();
// Use the Automatically generated key for Encryption.
return ASCIIEncoding.ASCII.GetString(desCrypto.Key);
}
}
public class EncryptionHelper
{
public static void EncryptFile(string sInputFilename, string sOutputFilename, string sKey)
{
//GCHandle gch = GCHandle.Alloc(sKey, GCHandleType.Pinned);
FileStream fsInput = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename,
FileMode.Create,
FileAccess.Write);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.Padding = PaddingMode.PKCS7;
//DES.Padding = PaddingMode.ANSIX923;
ICryptoTransform desencrypt = DES.CreateEncryptor();
CryptoStream cryptostream = new CryptoStream(fsEncrypted,
desencrypt,
CryptoStreamMode.Write);
byte[] bytearrayinput = new byte[fsInput.Length];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Flush();
cryptostream.Close();
fsInput.Flush();
fsInput.Close();
fsEncrypted.Close();
}
public static void DecryptFile(string sInputFilename, string sOutputFilename, string sKey)
{
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
//A 64 bit key and IV is required for this provider.
//Set secret key For DES algorithm.
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
//Set initialization vector.
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
//Create a file stream to read the encrypted file back.
FileStream fsread = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename,
FileMode.Create,
FileAccess.Write);
//Create a DES decryptor from the DES instance.
ICryptoTransform desdecrypt = DES.CreateDecryptor();
//Create crypto stream set to read and do a
//DES decryption transform on incoming bytes.
CryptoStream cryptostreamDecr = new CryptoStream(fsread,
desdecrypt,
CryptoStreamMode.Read);
byte[] fileData = new byte[fsread.Length];
cryptostreamDecr.Read(fileData, 0, (int)fsread.Length);
fsEncrypted.Write(fileData, 0, fileData.Length);
fsread.Flush();
fsread.Close();
fsEncrypted.Flush();
fsEncrypted.Close();
cryptostreamDecr.Flush();
cryptostreamDecr.Close();
}
}
}
The above code works fine for doc,xls,ppt,txt files but it currupts .xlsx,pptx and docx files . When i try to open the file it prompts a repair window saying the file is currupted .. Any idea ?

I am facing the same problem however when I used a buffer of size 1 (useless) the problem disappeared, I believe there is a bunch of extra bytes added and Office suite software can detect such tampering =\

Related

Decrypt RSA encrypted value generated from .net in Android [duplicate]

I have gone through many posts here but did not find the right solution. I want to decrypt a value encrypted in c# .net from Android.
I have successfully decrypted in .net platform using the following code snippet
public static void Main()
{
string _privateKey = Base64Decode("myprivatekey");
var rsa = new RSACryptoServiceProvider();
string data = "198,47,144,175,154,47,194,175,242,41,212,150,220,177,198,161,236,36,197,62,18,111,21,244,232,245,90,234,195,169,141,195,139,199,131,163,26,124,246,50,102,229,73,148,18,110,170,145,112,237,23,123,226,135,158,206,71,116,9,219,56,96,140,19,180,192,80,29,63,160,43,127,204,135,155,67,46,160,225,12,85,161,107,214,104,218,6,220,252,73,252,92,152,235,214,126,245,126,129,150,49,68,162,120,237,246,27,25,45,225,106,201,251,128,243,213,250,172,26,28,176,219,198,194,7,202,34,210";
var dataArray = data.Split(new char[] { ',' });
byte[] dataByte = new byte[dataArray.Length];
for (int i = 0; i < dataArray.Length; i++)
{
dataByte[i] = Convert.ToByte(dataArray[i]);
}
rsa.FromXmlString(_privateKey);
var decryptedByte = rsa.Decrypt(dataByte, false);
Console.WriteLine(_encoder.GetString(decryptedByte));
}
Now I want to do the same process in Android app. Please can somebody guide me through this?
I have tried the following code but its throwing javax.crypto.IllegalBlockSizeException: input must be under 128 bytes exception
String modulusString = "hm2oRCtP6usJKYpq7o1K20uUuL11j5xRrbV4FCQhn/JeXLT21laKK9901P69YUS3bLo64x8G1PkCfRtjbbZCIaa1Ci/BCQX8nF2kZVfrPyzcmeAkq4wsDthuZ+jPInknzUI3TQPAzdj6gim97E731i6WP0MHFqW6ODeQ6Dsp8pc=";
String publicExponentString = "AQAB";
byte[] modulusBytes = Base64.decode(modulusString, DEFAULT);
byte[] exponentBytes = Base64.decode(publicExponentString, DEFAULT);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger publicExponent = new BigInteger(1, exponentBytes);
RSAPrivateKeySpec rsaPubKey = new RSAPrivateKeySpec(modulus, publicExponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey pubKey = fact.generatePrivate(rsaPubKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] plainBytes = result.getBytes("UTF-16LE");
byte[] cipherData = cipher.doFinal(plainBytes);
String encryptedStringBase64 = Base64.decode(cipherData, DEFAULT).toString();

Extracting AES encrypted zip to MemoryStream

I am developing a process to compress and encrypt a byte array in my desktop application and send it via a WebMethod to my web application, then uncompress/unencrypt it back to a byte array. I am currently attempting to do this with SharpZipLib. The compression of the file seems to be working as expected. I am able to save the file to disk and extract it using 7zip without issue.
The problem I am having is when I receive the byte array on my web server and attempt to extract it.
I use the CompressData method to compress the data on the desktop side.
private byte[] CompressData(byte[] data, string password)
{
MemoryStream input = new MemoryStream(data);
MemoryStream ms = new MemoryStream();
ZipOutputStream os = new ZipOutputStream(ms);
os.SetLevel(9);
if (!string.IsNullOrEmpty(password)) os.Password = password;
ZipEntry entry = new ZipEntry("data")
{
DateTime = DateTime.Now
};
if (!string.IsNullOrEmpty(password)) entry.AESKeySize = 256;
os.PutNextEntry(entry);
StreamUtils.Copy(input, os, new byte[4096]);
os.CloseEntry();
os.IsStreamOwner = false;
os.Close();
ms.Position = 0;
return ms.ToArray();
}
I am using the following code to extract the data on the server end (taken almost verbatim from the SharpZipLib examples):
private byte[] DoRebuildData(byte[] data, string password)
{
MemoryStream inStream = new MemoryStream(data);
MemoryStream outputMemStream = new MemoryStream();
ZipOutputStream zipOut = new ZipOutputStream(outputMemStream)
{
IsStreamOwner = false // False stops the Close also Closing the underlying stream.
};
zipOut.SetLevel(3);
zipOut.Password = password; // optional
RecursiveExtractRebuild(inStream, zipOut);
inStream.Close();
// Must finish the ZipOutputStream to finalise output before using outputMemStream.
zipOut.Close();
outputMemStream.Position = 0;
return outputMemStream.ToArray();
}
// Calls itself recursively if embedded zip
//
private void RecursiveExtractRebuild(Stream str, ZipOutputStream os)
{
ZipFile zipFile = new ZipFile(str)
{
IsStreamOwner = false
};
foreach (ZipEntry zipEntry in zipFile)
{
if (!zipEntry.IsFile)
continue;
String entryFileName = zipEntry.Name; // or Path.GetFileName(zipEntry.Name) to omit folder
// Specify any other filtering here.
Stream zipStream = zipFile.GetInputStream(zipEntry);
// Zips-within-zips are extracted. If you don't want this and wish to keep embedded zips as-is, just delete these 3 lines.
if (entryFileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
{
RecursiveExtractRebuild(zipStream, os);
}
else
{
ZipEntry newEntry = new ZipEntry(entryFileName);
newEntry.DateTime = zipEntry.DateTime;
newEntry.Size = zipEntry.Size;
// Setting the Size will allow the zip to be unpacked by XP's built-in extractor and other older code.
os.PutNextEntry(newEntry);
StreamUtils.Copy(zipStream, os, new byte[4096]);
os.CloseEntry();
}
}
}
The expected result is to get back my original byte array on the server.
On the server, when it comes to the line:
Stream zipStream = zipFile.GetInputStream(zipEntry);
I receive the error 'No password available for AES encrypted stream.'
The only place I see to set a password is in the ZipOutputStream object, and I have checked at runtime, and this is set appropriately.
When unpacking, the password must be assigned to the password-property of the ZipFile-instance, i.e. it must be set in the RecursiveExtractRebuild-method (for this the password has to be added as an additional parameter):
zipFile.Password = password;
as shown in this example.
It should be noted that the current DoRebuildData-method doesn't actually unpack the data, but re-packs it into a new zip. The (optional) line in the DoRebuildData-method:
zipOut.Password = password;
does not specify the password for the unpacking (i.e. for the old zip), but defines the password for the new zip.

Java TripleDES PKCS5Padding decryption to C# - bad data / padding error

I'm trying to write the C# equivalent for the following Java code:
protected static final String DES_ECB_PKCS5PADDING = "DESede/ECB/PKCS5Padding";
public static String decryptValueDirect(String value, String key)
throws NoSuchAlgorithmException, NoSuchPaddingException,
GeneralSecurityException, IllegalBlockSizeException,
BadPaddingException {
byte[] bytes = Base64.decodeBase64(value);
Cipher cipher = Cipher.getInstance(DES_ECB_PKCS5PADDING);
cipher.init(Cipher.DECRYPT_MODE, convertSecretKey(key.getBytes()));
byte[] decryptedValue = cipher.doFinal(bytes);
String nstr = new String(decryptedValue);
return nstr;
}
protected static SecretKey convertSecretKey(byte[] encryptionKey) throws GeneralSecurityException {
if (encryptionKey == null || encryptionKey.length == 0)
throw new IllegalArgumentException("Encryption key must be specified");
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(TRIPLEDES);
KeySpec keySpec = new DESedeKeySpec(encryptionKey);
return keyFactory.generateSecret(keySpec);
}
The source text is a base64 encoded, then encrypted and then base64 encoded for transport on a rabbit queue. Our vendor who handles the encryption provided the above for decryption in Java, but has no idea about C#.
The only input on the encryption side is a key, a random string. We use the same string for encryption/decryption 012345678901234567890123456789 in our dev env. That is the only input, no salt, hashing (that i see) or pw iterations. The only requirement is that it is at least 24 chars long.
My C# code is below and a fiddle of my attempt is here.
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public class Program
{
public static void Main()
{
//Message Data value
//We are using encrypted multibyte.
string myData = #"ROE8oYeV7B6faUsvfIx0Xe55vSs9IR5DlWGRbSM+lmKmLcaJsA13VudwWlAEYtLUD8+nMXShky0grSxsk0Z9cQe5V45XnAIfUhnyzI9a0jtMFC8XnIZ5dbclPO/V73QnieIZDkbNV5cPo3BM+l79ai96KB/gkF3xuerFPxvWejtPyWbOyO+FfNyFps4gAYDITsYIAEH39VP4eipmQ5zc18BA39lajQ3UaVewSxz7H+x3Ooe2SzJT/TQWRkioJSEFwexqzkHiLOQ0MOCIVD9xTWpLYnsL3LMwyF6H8f0PY4Fc57LVGhvUZ7dsB9NWUAnmG3uqbsonNFVhuXyvJTWNyFOHwFzOMx6XDLJJFHGZhaHg2VrescfnpUtonQY08RgojBngyJNRqK8URAvI3bqKq8Y7F/9HmEtMIIQe6KuuTmU=";
string myKey = "012345678901234567890123456789";//Development Env Key.
Console.WriteLine("Decrypt1:");
string s = Decrypt1(myData, myKey);
Console.ReadLine();
}
public static string Decrypt1(string value, string decryptionKey)
{
string decryptString = "";
TripleDESCryptoServiceProvider tDESalg = new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider hashMD5Provider = new MD5CryptoServiceProvider();
try
{
byte[] decodedData = Convert.FromBase64String(value);
tDESalg.Mode = CipherMode.ECB;
tDESalg.Padding = PaddingMode.PKCS7;//According to MS, same as PKCS5PADDING
byte[] Key = hashMD5Provider.ComputeHash(Encoding.UTF8.GetBytes(decryptionKey));
//byte[] IV = tDESalg.IV;
byte[] IV = new byte[tDESalg.BlockSize / 8]; //The size of the IV property must be the same as the BlockSize property divided by 8
var memoryStream = new MemoryStream(decodedData);
var cryptoStream = new CryptoStream(memoryStream, tDESalg.CreateDecryptor(Key, IV), CryptoStreamMode.Read);
var reader = new StreamReader(cryptoStream);
decryptString = reader.ReadToEnd();
byte[] decryptData = Convert.FromBase64String(decryptString);
}
catch (Exception e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message + e.StackTrace);
return null;
}
return decryptString;
}
}
Searching seems to point to the same answer, the key, encoding, ... all must be the same. I just don't know what that would be the equivalent for the Java source provided. :) Any suggestions will be helpful.
MD5 has a 16-byte output, Triple DES (3DES) requires a 24-byte key. There is a key size mis-match.
The C# and Java key derivations are substantially different:
C#:
byte[] Key = hashMD5Provider.ComputeHash(Encoding.UTF8.GetBytes(decryptionKey));
returns 16-bytes.
Java:
SecretKeyFactory.getInstance(TRIPLEDES)
returns 24-bytes.
There is a key option (2TDEA) where a 16-byte key is used and the first 8-bytes will be duplicated to create the last 8-bytes. NIST has deprecated this option.
Some implementations will accept a 16-byte key and extend the key to 24-bytes and some will not. You should provide all 24-bytes to 3DES, do not rely on an implementation to create the 24-byte key.
Note: The question was updated so it is not clear that the the actual encrytpion key is derived.

AES Encrypt / Decrypt byte[]

I am trying to encrypt a byte[] using the following methods but when I decrypt it my byte[] is bigger than when I started and I think its to do with padding but I am not sure how to solve it.
The method isnt finished yet (I know its bad to append the key + iv like my example but its for testing purpose to get it working before I move on).
So when I try to open the file afterwards (tested with MS Word file) I get a message saying the file is damaged and would I like to repair it.
Encrypt Method
public byte[] Encrypt(byte[] dataToEncrypt) {
// Check arguments.
if (dataToEncrypt == null || dataToEncrypt.Length <= 0) {
throw new ArgumentNullException("dataToEncrypt");
}
byte[] encryptedData;
byte[] key;
byte[] iv;
// Create an Aes object
using (Aes aesAlg = Aes.Create()) {
key = aesAlg.Key;
iv = aesAlg.IV;
// Create a encrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream memoryStream = new MemoryStream()) {
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) {
cryptoStream.Write(dataToEncrypt, 0, dataToEncrypt.Length);
cryptoStream.FlushFinalBlock();
encryptedData = memoryStream.ToArray();
}
}
}
byte[] result = new byte[encryptedData.Length + KEY_SIZE + IV_SIZE];
Buffer.BlockCopy(key, 0, result, 0, KEY_SIZE);
Buffer.BlockCopy(iv, 0, result, KEY_SIZE, IV_SIZE);
Buffer.BlockCopy(encryptedData, 0, result, KEY_SIZE + IV_SIZE, encryptedData.Length);
return result;
}
Decrypt Method
public byte[] Decrypt(byte[] encryptedData) {
// Check arguments.
if (encryptedData == null || encryptedData.Length <= 0) {
throw new ArgumentNullException("encryptedData");
}
byte[] storedKey = new byte[KEY_SIZE];
byte[] storedIV = new byte[IV_SIZE];
byte[] dataToDecrypt = new byte[encryptedData.Length - (KEY_SIZE + IV_SIZE)];
Buffer.BlockCopy(encryptedData, 0, storedKey, 0, KEY_SIZE);
Buffer.BlockCopy(encryptedData, KEY_SIZE, storedIV, 0, IV_SIZE);
Buffer.BlockCopy(encryptedData, KEY_SIZE + IV_SIZE, dataToDecrypt, 0, encryptedData.Length - (KEY_SIZE + IV_SIZE));
byte[] decryptedData = null;
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (Aes aesAlg = Aes.Create()) {
aesAlg.Key = storedKey;
aesAlg.IV = storedIV;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream memoryStream = new MemoryStream(dataToDecrypt)) {
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) {
cryptoStream.Read(dataToDecrypt, 0, dataToDecrypt.Length);
decryptedData = memoryStream.ToArray();
}
}
}
return decryptedData;
}
You are assuming that the entire buffer is plaintext data as well. You should only return that part of the buffer that contains the plaintext data (using the response of Read to see how much bytes are returned). The encrypted data is usually larger because of the padding.
As a single read method isn't good practice with regards to stream handling. You need to read until the end of the stream is reached. Otherwise you may go from having too much data to having too little.

Implementing PHP AES Function in .NET (C#)

I have given a task in which I need to encrypt an user's ID using AES encryption, what they want is I need to pass in a parameter in a website just like this.
URL : http://www.site.com/event/sample.jce
Parameter : ?param= encrypted text
aside from that there was an attched php sample that they want me to follow to encrypt but I don't have an idea on how to convert this one in .NET
function getEncrypt($sStr, $sKey, $sIV){
$sCipher = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $sKey, $sStr, MCRYPT_MODE_CFB, $sIV);
return bin2hex($sCipher);
}
$sStr = "13410##13";
$sKey = "mediaservice1234";
$sKey = "kjcemsdev3jangho"; // Do not change
$sIV = "fs0tjwkdgh0akstp"; // Do not change
$tmp= getEncrypt($sStr, $sKey, $sIV);
Could somebody help me to understand this codes? or better if they could help me to convert this one on .NEt code? Thanks. :)
Try this, you need to set the FeedbackSize and Padding:
public static string Encrypt(string plaintext)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
//RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.FeedbackSize = 8;
rijndaelCipher.Mode = CipherMode.CFB;
rijndaelCipher.KeySize = 128;
// rijndaelCipher.BlockSize = 128;
rijndaelCipher.BlockSize = 128;
rijndaelCipher.Padding = PaddingMode.Zeros;
byte[] plaintextByte = System.Text.Encoding.ASCII.GetBytes(plaintext);
//Rfc2898DeriveBytes
ASCIIEncoding textConverter = new ASCIIEncoding();
rijndaelCipher.Key = textConverter.GetBytes(PRIVATEKEY); ;
rijndaelCipher.IV = Convert.FromBase64String(PRIVATEIV);
ICryptoTransform encryptor = rijndaelCipher.CreateEncryptor();
//http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(VS.80).aspx
//Encrypt the data.
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
//Convert the data to a byte array.
byte[] toEncrypt = textConverter.GetBytes(plaintext);
//Write all data to the crypto stream and flush it.
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
byte[] encrypted = new byte[16];
//Get encrypted array of bytes.
encrypted = msEncrypt.ToArray();
return Convert.ToBase64String(encrypted);
}
Here you can find some more information about using the AES encryption in .net:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged%28VS.80%29.aspx
The code is pretty straight forward.

Resources