I am trying to sign a PDF Document using two web services in two servers. But it is showing "Document has been altered or corrupt since it was signed" in Adobe Reader. Can anybody suggest what is wrong in following code.
PROCEDURE
1. Web service (WS) on Server A, Generate hash from PDF and sent to WS on Server B for signing.
2. WS on Server B signs hash.
3. WS on Server A receives signed hash and Embed in PDF document.
CODE
GENERATE HASH
private PDFHashData generateHash(byte[] content, string userName)
{
PdfReader reader = new PdfReader(content);
MemoryStream ms = new MemoryStream();
PdfStamper stamper = PdfStamper.CreateSignature(reader, ms, '\0');
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.SetVisibleSignature(new Rectangle(500, 150, 400, 200), 1, signatureFieldName);
appearance.SignDate = DateTime.Now;
appearance.Reason = Reason;
appearance.Location = Location;
appearance.Contact = Contact;
StringBuilder buf = new StringBuilder();
buf.Append("Digitally signed by");
buf.Append("\n");
buf.Append(userName);
buf.Append("\n");
buf.Append("Date: " + appearance.SignDate);
appearance.Layer2Text = buf.ToString();
appearance.Acro6Layers = true;
appearance.CertificationLevel = 0;
IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.SignExternalContainer(appearance, external, 8192);
byte[] hash = SHA256Managed.Create().ComputeHash(appearance.GetRangeStream());
StringBuilder hex = new StringBuilder(hash.Length * 2);
foreach (byte b in hash)
hex.AppendFormat("{0:x2}", b);
PDFHashData phData= new PDFHashData();
phData.Hash = hex.ToString();
phData.Content = Convert.ToBase64String(ms.ToArray());
return phData;
}
SIGN HASH
byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
private Stream getCertificate()
{
// Base 64 byte - PFX file with private key
return new MemoryStream(Convert.FromBase64String("..................................AgIEAA=="));
}
protected void Page_Load(object sender, EventArgs e)
{
Stream stream = Request.InputStream;
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
byte[] hash = StringToByteArray(Encoding.UTF8.GetString(buffer));
Pkcs12Store store = new Pkcs12Store(getCertificate(), "*******".ToCharArray());
String alias = "";
foreach (string al in store.Aliases)
if (store.IsKeyEntry(al) && store.GetKey(al).Key.IsPrivate)
{
alias = al;
break;
}
AsymmetricKeyEntry pk = store.GetKey(alias);
X509CertificateEntry[] chain = store.GetCertificateChain(alias);
List<Org.BouncyCastle.X509.X509Certificate> c = new List<Org.BouncyCastle.X509.X509Certificate>();
foreach (X509CertificateEntry en in chain)
{
c.Add(en.Certificate);
}
PrivateKeySignature signature = new PrivateKeySignature(pk.Key, "SHA1");
String hashAlgorithm = signature.GetHashAlgorithm();
PdfPKCS7 sgn = new PdfPKCS7(null, c, hashAlgorithm, false);
DateTime signingTime = DateTime.Now;
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
byte[] extSignature = signature.Sign(sh);
sgn.SetExternalDigest(extSignature, null, signature.GetEncryptionAlgorithm());
Response.Write(Convert.ToBase64String(sgn.GetEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS)));
}
EMBED SIGNATURE TO PDF
private byte[] signPDF(byte[] content, string userName, byte[] pk)
{
PdfReader reader = new PdfReader(content);
MemoryStream os = new MemoryStream();
IExternalSignatureContainer external = new MyExternalSignatureContainer(pk);
MakeSignature.SignDeferred(reader, signatureFieldName, os, external);
return os.ToArray();
}
For those who are interested I am posting the answer.
I ended up using itextsharp 5.5.10. Code is given below,
Initialize PDF object
public PDFSigning(byte[] Content, string UserName)
{
content = Content;
reader = new PdfReader(content);
ms = new MemoryStream();
stamper = PdfStamper.CreateSignature(reader, ms, '\0');
appearance = stamper.SignatureAppearance;
userName = UserName;
}
private Stream getCertificate()
{
return new MemoryStream(Convert.FromBase64String("************************=="));
}
Generate hash
private string generateHash()
{
appearance.SetVisibleSignature(new Rectangle(500, 150, 400, 200), 1, signatureFieldName);
appearance.SignDate = DateTime.Now;
appearance.Reason = Reason;
appearance.Location = Location;
appearance.Contact = Contact;
StringBuilder buf = new StringBuilder();
buf.Append("Digitally signed by");
buf.Append("\n");
buf.Append(userName);
buf.Append("\n");
buf.Append("Date: " + appearance.SignDate);
appearance.Layer2Text = buf.ToString();
appearance.Acro6Layers = true;
appearance.CertificationLevel = 0;
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED)
{
Date = new PdfDate(appearance.SignDate),
Name = userName
};
dic.Reason = appearance.Reason;
dic.Location = appearance.Location;
dic.Contact = appearance.Contact;
appearance.CryptoDictionary = dic;
Dictionary<PdfName, int> exclusionSizes = new Dictionary<PdfName, int>();
exclusionSizes.Add(PdfName.CONTENTS, (csize * 2) + 2);
appearance.PreClose(exclusionSizes);
HashAlgorithm sha = new SHA256CryptoServiceProvider();
Stream s = appearance.GetRangeStream();
int read = 0;
byte[] buff = new byte[0x2000];
while ((read = s.Read(buff, 0, 0x2000)) > 0)
{
sha.TransformBlock(buff, 0, read, buff, 0);
}
sha.TransformFinalBlock(buff, 0, 0);
StringBuilder hex = new StringBuilder(sha.Hash.Length * 2);
foreach (byte b in sha.Hash)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
Sign hash
public byte[] SignMsg(string hexhash)
{
byte[] hash = hexToByteArray(hexhash);
Pkcs12Store store = new Pkcs12Store(getCertificate(), "*********".ToCharArray());
String alias = "";
foreach (string al in store.Aliases)
if (store.IsKeyEntry(al) && store.GetKey(al).Key.IsPrivate)
{
alias = al;
break;
}
AsymmetricKeyEntry pk = store.GetKey(alias);
X509CertificateEntry[] chain = store.GetCertificateChain(alias);
List<Org.BouncyCastle.X509.X509Certificate> c = new List<Org.BouncyCastle.X509.X509Certificate>();
foreach (X509CertificateEntry en in chain)
{
c.Add(en.Certificate);
}
PrivateKeySignature signature = new PrivateKeySignature(pk.Key, "SHA256");
String hashAlgorithm = signature.GetHashAlgorithm();
PdfPKCS7 sgn = new PdfPKCS7(null, c, hashAlgorithm, false);
DateTime signingTime = DateTime.Now;
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
byte[] extSignature = signature.Sign(sh);
sgn.SetExternalDigest(extSignature, null, signature.GetEncryptionAlgorithm());
return sgn.GetEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);
}
Sign PDF
private byte[] signPDF(byte[] pk)
{
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);
//System.IO.File.WriteAllBytes(System.Web.HttpContext.Current.Server.MapPath("~/temp.pdf"), ms.ToArray());
return ms.ToArray();
}
Related
I add to pdf document X509certificate and visible signature element using iTextSharp. The code does not cause errors, but while i open signed document, appears message that the certificate is invalid because document was corrupted after signing. I added the certificate to the trusted list. What could be the problem?
The code I used here
public void Sign()
{
X509Certificate2 certificate = GetSert();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(certificate) };
PdfReader reader = new PdfReader(#"C:\ Test.pdf");
PdfDictionary dict = reader.GetPageN(reader.NumberOfPages);
IList<iTextSharp.text.Image> list = GetImagesFromPdfDict(dict, reader);
PdfStamper stp = PdfStamper.CreateSignature(reader, new
FileStream(NewFP, FileMode.Create), '\0', null, true);
iTextSharp.text.Rectangle cropBox = reader.GetCropBox(reader.NumberOfPages);
PdfSignatureAppearance sap = stp.SignatureAppearance;
iTextSharp.text.Rectangle signPosition = new iTextSharp.text.Rectangle(cropBox.GetLeft(reader.NumberOfPages) + 55, Y, cropBox.GetLeft(reader.NumberOfPages) + 260, Y - 80);
byte[] pk = certificate.GetRawCertData();
sap.SignDate = DateTime.Now;
sap.Acro6Layers = true;
sap.Layer4Text = "";
sap.Layer2Text = "";
sap.SignatureGraphic = list[0];
sap.Render =
PdfSignatureAppearance.SignatureRender.Graphic;
PdfSignature dic = new PdfSignature(PdfName.ADBE_X509_RSA_SHA1,
PdfName.ADBE_X509_RSA_SHA1);
dic.Cert = certificate.GetRawCertData();
dic.Date = new PdfDate(sap.SignDate);
dic.Name = PdfPKCS7.GetSubjectFields(chain[0]).GetField("CN");
sap.CryptoDictionary = dic;
int csize = pk.Length;
Dictionary<PdfName, int> ex = new Dictionary<PdfName, int>(1);
ex.Add(PdfName.CONTENTS, csize * 2 + 2);
exc[PdfName.CONTENTS] = csize * 2 + 2;
sap.CertificationLevel = PdfSignatureAppearance.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS;
sap.SetVisibleSignature(signPosition, reader.NumberOfPages, null);
sap.SetCrypto(null, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
sap.PreClose(ex);
byte[] outc = new byte[csize];
PdfDictionary dic2 = new PdfDictionary();
Array.Copy(pk, 0, outc, 0, pk.Length);
dic2.Put(PdfName.CONTENTS, new
PdfString(outc).SetHexWriting(true));
sap.Close(dic2);
}
And my signed document here
30.11.2020
I try to enctypted current range stream using next code
sap.PreClose(ex);
Stream s = sap.GetRangeStream();
MemoryStream ss = new MemoryStream();
int read = 0;
int len = (int)s.Length+1;
byte[] buff = new byte[len];
MessageBox.Show(s.Length.ToString());
while ((read = s.Read(buff, 0, len)) > 0)
{
ss.Write(buff, 0, read);
}
byte[] ToS = ss.ToArray();
ContentInfo content = new ContentInfo(ToS);
SignedCms signedCms = new SignedCms(content, false);
CmsSigner signer = new CmsSigner(
SubjectIdentifierType.SubjectKeyIdentifier,
certificate);
signedCms.ComputeSignature(signer);
byte[] signedbytes = signedCms.Encode();
// Set signature to document
byte[] outc = new byte[signedbytes.Length];
PdfDictionary dic2 = new PdfDictionary();
Array.Copy(signedbytes, 0, outc, 0, signedbytes.Length);
dic2.Put(PdfName.CONTENTS, new PdfString(outc).SetHexWriting(true));
sap.Close(dic2);
but it works worse than the previous one. I got error:
Maybe signing incorrectly? My certificate alghoritm is sha256RSA
//09.12.2020
I achieved success using the following code:
public void PrepareSignatureAndGetHash(X509Certificate2 cert)
{
using (var reader = new PdfReader(#"C:\Test.pdf"))
{
using (var fileStream = new
FileStream(#"C:\Output.pdf", FileMode.Create))
{
using (var stamper = PdfStamper.CreateSignature(reader, fileStream, '0', null, true))
{
var signatureAppearance = stamper.SignatureAppearance;
Rectangle cropBox = reader.GetCropBox(reader.NumberOfPages);
Rectangle signPosition = new Rectangle(cropBox.GetRight(0) - 20, cropBox.GetBottom(0), cropBox.GetRight(0) - 250, cropBox.GetBottom(0) + 80);
signatureAppearance.SetVisibleSignature(signPosition, reader.NumberOfPages, null);
signatureAppearance.Reason = "Sig";
signatureAppearance.Layer2Text = "";
signatureAppearance.Image = iTextSharp.text.Image.GetInstance(#"C:\Stamp.png");
if (!cert.HasPrivateKey) { MessageBox.Show("Не найдено закрытого ключа"); }
var keyPair = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(cert.PrivateKey).Private;
Org.BouncyCastle.X509.X509Certificate bcCert = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(cert);
var chain = new List<Org.BouncyCastle.X509.X509Certificate> { bcCert };
IExternalSignature signature = new PrivateKeySignature(keyPair, "SHA-256");
MakeSignature.SignDetached(signatureAppearance, signature, chain, null, null, null, 0, CryptoStandard.CMS);
}
}
}
}
Using a low level code I couldn't sign correctly
I need to sign pdf with external web service. But there is an error on signed pdf like Document has been altered or corrupted since it was signed.
static void Main(string[] args)
{
//StreamSign();
PdfReader reader = new PdfReader(#"E:\pdf-exampleSign\example.pdf");
//MemoryStream os = new MemoryStream();
FileStream os = File.OpenWrite(#"E:\pdf-exampleSign\example_tmp.pdf");
PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0');
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(36, 748, 144, 780), 1, "Signature");
IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.SignExternalContainer(appearance, external, 20000);
byte[] hash = SHA256Managed.Create().ComputeHash(appearance.GetRangeStream());
StringBuilder builder = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
builder.Append(hash[i].ToString("x2"));
}
var hex = builder.ToString();
//HERE IS THE SERVER SIDE BASE64 STRING I GOT
string ServerSideSignedBytes = "MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgE.....";
byte[] signbytes = Convert.FromBase64String(ServerSideSignedBytes);
X509Certificate2 certt = new X509Certificate2(signbytes);
var cert = new Org.BouncyCastle.X509.X509CertificateParser().ReadCertificate(certt.GetRawCertData());
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[1];
chain[0] = cert;
using (PdfReader prereader = new PdfReader(#"E:\pdf-exampleSign\example_tmp.pdf"))
{
using (FileStream preos = File.OpenWrite(#"E:\pdf-exampleSign\example_signed.pdf"))
{
IExternalSignatureContainer externallast = new MyExternalSignatureContainer(signbytes, chain);
MakeSignature.SignDeferred(prereader, "Signature", preos, externallast);
}
}
}
public class MyExternalSignatureContainer : IExternalSignatureContainer
{
protected byte[] sig;
protected Org.BouncyCastle.X509.X509Certificate[] chain;
public MyExternalSignatureContainer(byte[] sig, Org.BouncyCastle.X509.X509Certificate[] chain)
{
this.sig = sig;
this.chain = chain;
}
public byte[] Sign(Stream s)
{
return sig;
}
public void ModifySigningDictionary(PdfDictionary signDic) { }
}
Kindly help me to resolve this issue. It is showing error shows cannot access the closed stream.
I am using memory stream from RLDC and watermarked first then the process of digital sign begin.
I think there is an issue in the last 6 lines or maybe I am not closing the variables properly.
What am I doing wrong here?
public static byte[] AddWatermark(byte[] bytes, BaseFont baseFont, string watermarkText)
{
using (var ms = new MemoryStream(10 * 1024))
{
using (var reader = new PdfReader(bytes))
using (var stamper = new PdfStamper(reader, ms))
{
var pages = reader.NumberOfPages;
for (var i = 1; i <= pages; i++)
{
var dc = stamper.GetOverContent(i);
AddWaterMarkText(dc, watermarkText, baseFont, 100, 45, BaseColor.GRAY, reader.GetPageSizeWithRotation(i));
// Keypair Generator
RsaKeyPairGenerator kpGenerator = new RsaKeyPairGenerator();
kpGenerator.Init(new KeyGenerationParameters(new SecureRandom(), 2048));
// Create a keypair
AsymmetricCipherKeyPair kp = kpGenerator.GenerateKeyPair();
// Certificate Generator
X509V3CertificateGenerator cGenerator = new X509V3CertificateGenerator();
cGenerator.SetSerialNumber(BigInteger.ProbablePrime(120, new Random()));
cGenerator.SetSubjectDN(new X509Name("CN=" + "abc.com"));
cGenerator.SetIssuerDN(new X509Name("CN=" + "Aalok"));
cGenerator.SetNotBefore(DateTime.Now);
cGenerator.SetNotAfter(DateTime.Now.Add(new TimeSpan(365, 0, 0, 0))); // Expire in 1 year
cGenerator.SetSignatureAlgorithm(HashType.SHA256withRSA.ToString()); // See the Appendix Below for info on the hash types supported by Bouncy Castle C#
cGenerator.SetPublicKey(kp.Public); // Only the public key should be used here!
Org.BouncyCastle.X509.X509Certificate cert = cGenerator.Generate(kp.Private); // Create a self-signed cert
byte[] encoded = cert.GetEncoded();
try
{
FileStream outStream = new FileStream("abc.der", FileMode.Create, FileAccess.ReadWrite);
{
outStream.Write(encoded, 0, encoded.Length);
}
}
catch (FileNotFoundException)
{
Console.WriteLine("File not found");
}
// Create the PKCS12 store
Pkcs12Store store = new Pkcs12StoreBuilder().Build();
// Add a Certificate entry
X509CertificateEntry certEntry = new X509CertificateEntry(cert);
store.SetCertificateEntry(cert.SubjectDN.ToString(), certEntry); // use DN as the Alias.
// Add a key entry
AsymmetricKeyEntry keyEntry = new AsymmetricKeyEntry(kp.Private);
store.SetKeyEntry(cert.SubjectDN.ToString() + "_key", keyEntry, new X509CertificateEntry[] { certEntry }); // Note that we only have 1 cert in the 'chain'
// Save to the file system
try
{
var filestream = new FileStream(#"abc.pfx", FileMode.Create, FileAccess.ReadWrite);
{
store.Save(filestream, "123".ToCharArray(), new SecureRandom());
}
}
catch (FileNotFoundException)
{
Console.WriteLine("File not found");
}
String alias = "";
ICollection<Org.BouncyCastle.X509.X509Certificate> chain = new List<Org.BouncyCastle.X509.X509Certificate>();
// searching for private key
foreach (string al in store.Aliases)
if (store.IsKeyEntry(al) && store.GetKey(al).Key.IsPrivate)
{
alias = al;
break;
}
AsymmetricKeyEntry pk = store.GetKey(alias);
foreach (X509CertificateEntry c in store.GetCertificateChain(alias).ToList())
{
chain.Add(c.Certificate);
}
RsaPrivateCrtKeyParameters parameters = pk.Key as RsaPrivateCrtKeyParameters;
PdfReader read = new PdfReader(bytes);
// PdfStamper.CreateSignature(read, ms, '\0');
PdfStamper stamp = PdfStamper.CreateSignature(read, ms, '\0');
// Creating the appearance
PdfSignatureAppearance appearance = stamp.SignatureAppearance;
appearance.Reason = "My reason for signing";
appearance.Location = "The middle of nowhere";
// appearance.SignDate = DateTime.Now;
appearance.SetVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
// Creating the signature
IExternalSignature pks = new PrivateKeySignature(parameters, DigestAlgorithms.SHA256);
MakeSignature.SignDetached(appearance, pks, chain, null, null, null, 0, CryptoStandard.CMS);
stamp.Close();
read.Close();
break;
}
//stamper.Close();
reader.Close();
ms.Close();
}
return ms.ToArray();
}
}
I am trying to create a protected spreadsheet document with OpenXML SDK. However, the WorkbookHashValue generated is not correct and thus the workbook cannot be unprotected.
var password = Encoding.UTF8.GetBytes("123");
var salt = new byte[16];
new RNGCryptoServiceProvider().GetNonZeroBytes(salt);
var spinCount = 100000U;
using (var document = SpreadsheetDocument.Create("text.xlsx", SpreadsheetDocumentType.Workbook))
{
var workbookPart = document.AddWorkbookPart();
var workbook = new Workbook();
WorkbookProtection workbookProtection = new WorkbookProtection()
{
LockStructure = true,
WorkbookAlgorithmName = "SHA-512",
WorkbookHashValue = Convert.ToBase64String(GetPasswordHash(password, salt, spinCount)),
WorkbookSaltValue = Convert.ToBase64String(salt),
WorkbookSpinCount = spinCount
};
var sheets = new Sheets();
var sheet = new Sheet
{
Name = "Sheet 1",
SheetId = 1U,
Id = "rId1"
};
sheets.Append(sheet);
workbook.Append(workbookProtection);
workbook.Append(sheets);
workbookPart.Workbook = workbook;
var worksheetPart = workbookPart.AddNewPart<WorksheetPart>("rId1");
var worksheet = new Worksheet();
var sheetData = new SheetData();
worksheet.Append(sheetData);
worksheetPart.Worksheet = worksheet;
}
private byte[] GetPasswordHash(byte[] password, byte[] salt, uint spinCount)
{
using (var sha512 = SHA512.Create())
{
var buffer = new byte[salt.Length + password.Length];
Array.Copy(salt, buffer, salt.Length);
Array.Copy(password, 0, buffer, salt.Length, password.Length);
byte[] hash = sha512.ComputeHash(buffer);
buffer = new byte[hash.Length + 4];
for (var i = 0U; i < spinCount; i++)
{
Array.Copy(hash, buffer, hash.Length);
Array.Copy(BitConverter.GetBytes(i), 0, buffer, hash.Length, 4);
hash = sha512.ComputeHash(buffer);
}
return hash;
}
}
The correct hash for password 123 with salt VAQd0dyl7U67APquHio1lQ== should be 2ZwXmW83qax0iUfzSkbhwAOVSDHAm6S/v9irWWTzdoFDgzO2Kc82P3Z9BAwbWqFLzN4rKaL0APOMzQ5tA7TBDw==, but the above code generated z5ebojaXN/sD4ps9yurRCpSTDp+kSuTz+HN2PyKmGuicNgszAPKxfsE+kTgOEbGhT/VqSbwTd++oyAJxJh0L3A==.
I tried comparing the source code of Apache POI and didn't found any mistakes
public static byte[] hashPassword(String password, HashAlgorithm hashAlgorithm, byte[] salt, int spinCount, boolean iteratorFirst) {
// If no password was given, use the default
if (password == null) {
password = Decryptor.DEFAULT_PASSWORD;
}
MessageDigest hashAlg = getMessageDigest(hashAlgorithm);
hashAlg.update(salt);
byte[] hash = hashAlg.digest(StringUtil.getToUnicodeLE(password));
byte[] iterator = new byte[LittleEndianConsts.INT_SIZE];
byte[] first = (iteratorFirst ? iterator : hash);
byte[] second = (iteratorFirst ? hash : iterator);
try {
for (int i = 0; i < spinCount; i++) {
LittleEndian.putInt(iterator, 0, i);
hashAlg.reset();
hashAlg.update(first);
hashAlg.update(second);
hashAlg.digest(hash, 0, hash.length); // don't create hash buffer everytime new
}
} catch (DigestException e) {
throw new EncryptedDocumentException("error in password hashing");
}
return hash;
}
(iteratorFirst is false for workbook protection)
The encoding used to get the password bytes should be UTF16LE
Encoding.Unicode.GetBytes("123");
I have created a page that encrypts two fields and sends it to another page where it is decrypted.
The problem is if I make my submit button send an smtp email to the user (rather than to page2.aspx itself) and they open the page in any other browser than the one that it was encrypted in, it no longer works.
For example: On page1.aspx there is an ID field, an email field, and a submit button. On submit it encrypts the ID field and sends it as a link (page2.aspx?query=ENCRYPTED DATA) where I can view the data. (This works if I stay in a specific browser)
The problem is I get a bad data error when I open the link in another browser. (Encrypted in Firefox then opening the link in Google Chrome) It throws the Bad Data server error.
Any ideas on how I can fix this issue? I want to be able to open the link from an email but allow cross browser activity using the encrypted link. Any solutions would be great. Thanks.
Here is the Encryption:
public string Encrypt(string message)
{
UTF8Encoding textConverter = new UTF8Encoding();
RC2CryptoServiceProvider rc2CSP = new RC2CryptoServiceProvider();
byte[] toEncrypt = textConverter.GetBytes(message);
ICryptoTransform encryptor = rc2CSP.CreateEncryptor(ScrambleKey, ScrambleIV);
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
byte[] length = new byte[4];
length[0] = (byte)(message.Length & 0xFF);
length[1] = (byte)((message.Length >> 8) & 0xFF);
length[2] = (byte)((message.Length >> 16) & 0xFF);
length[3] = (byte)((message.Length >> 24) & 0xFF);
csEncrypt.Write(length, 0, 4);
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
byte[] encrypted = msEncrypt.ToArray();
string b64 = Convert.ToBase64String(encrypted);
string b64mod = b64.Replace('+', '#');
return HttpUtility.UrlEncode(b64mod);
}
Here is the Email:
private void AutomatedEmail()
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString4"].ConnectionString);
DataTable dt = new DataTable();
con.Open();
SqlDataReader rd = null;
SqlCommand com = new SqlCommand("SELECT ID WHERE ID = #ID", con);
com.Parameters.AddWithValue("#ID", lblid.InnerText);
rd = com.ExecuteReader();
while (rd.Read())
{
string Query = "http://page2.aspx?query=" + Encrypt("ID=" + (rd["ID"].ToString()));
MailMessage message = new MailMessage();
message.To.Add(rd["OwnerEmail"].ToString());
message.From = new MailAddress("xxxxxxxxxxxxx");
message.Subject = "Test Email";
message.Body = "Test: " + Query;
SmtpClient smtp = new SmtpClient("xxxx");
smtp.Port = xxxx;
smtp.EnableSsl = false;
NetworkCredential netcre = new NetworkCredential("xxxx", "xxxx");
smtp.Credentials = netcre;
smtp.Send(message);
}
con.Close();
}
*****EDIT*****
Keys for Encryption/Decryption:
public byte[] ScrambleKey
{
set
{
byte[] key = value;
if (null == key)
{
key = ScrambleKey;
}
Session["ScrambleKey"] = key;
}
get
{
byte[] key = (byte[])Session["ScrambleKey"];
if (null == key)
{
RC2CryptoServiceProvider rc2 = new RC2CryptoServiceProvider();
rc2.GenerateKey();
key = rc2.Key;
Session["ScrambleKey"] = key;
}
return key;
}
}
public byte[] ScrambleIV
{
set
{
byte[] key = value;
if (null == key)
{
key = ScrambleIV;
}
Session["ScrambleIV"] = key;
}
get
{
byte[] key = (byte[])Session["ScrambleIV"];
if (null == key)
{
RC2CryptoServiceProvider rc2 = new RC2CryptoServiceProvider();
rc2.GenerateIV();
key = rc2.IV;
Session["ScrambleIV"] = key;
}
return key;
}
}
Receiving Page: Decryption:
public string Decrypt(string scrambledMessage)
{
UTF8Encoding textConverter = new UTF8Encoding();
RC2CryptoServiceProvider rc2CSP = new RC2CryptoServiceProvider();
string b64mod = HttpUtility.UrlDecode(scrambledMessage);
string b64 = b64mod.Replace('#', '+');
byte[] encrypted = Convert.FromBase64String(b64);
ICryptoTransform decryptor = rc2CSP.CreateDecryptor(ScrambleKey, ScrambleIV);
MemoryStream msDecrypt = new MemoryStream(encrypted);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
byte[] fromEncrypt = new byte[encrypted.Length - 4];
byte[] length = new byte[4];
csDecrypt.Read(length, 0, 4);
csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
int len = (int)length[0] | (length[1] << 8) | (length[2] << 16) | (length[3] << 24);
return textConverter.GetString(fromEncrypt).Substring(0, len);
}
public NameValueCollection DecryptQueryString(string scrambledMessage)
{
string queryString = Decrypt(scrambledMessage);
NameValueCollection result = new NameValueCollection();
char[] splitChar = new char[] { '&' };
char[] equalChar = new char[] { '=' };
foreach (string s in queryString.Split(splitChar))
{
string[] keyVal = s.Split(equalChar, 2);
string key = keyVal[0];
string val = String.Empty;
if (keyVal.Length > 1) val = keyVal[1];
result.Add(key, val);
}
return result;
}
Source Error: Line 112.
Line 110: byte[] length = new byte[4];
Line 111: csDecrypt.Read(length, 0, 4);
Line 112: csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
Line 113: int len = (int)length[0] | (length[1] << 8) | (length[2] << 16) | (length[3] << 24);
Line 114: return textConverter.GetString(fromEncrypt).Substring(0, len);