ssis-build
ssis-build copied to clipboard
SSIS 2017 are not supported when EncryptSensitiveWithPassword
this is the error when I try to build a SSIS 2017 project with EncryptSensitiveWithPassword Protection Level:
PS C:\Users\Administrator> . $ssisbuild $prj -Configuration "Development" -Password "aaa" SSIS Build Engine Copyright (c) 2017 Roman Tumaykin
Executing SSIS Build with the following arguments: Project File: c:\Users\administrator\source\repos\SSIS\SSIS\SSIS.dtproj -Password: (hidden) -Configuration: Development
Project parameters: Starting build. Loading project files from c:\Users\administrator\source\repos\SSIS\SSIS\SSIS.dtproj. ERROR: Specified initialization vector (IV) does not match the block size for this algorithm.
here some further investigation. on the left side the 2017 project version on the right side the 2016 project version:
the ssis 2017 project version has a SSIS:Algorithm but the 2016 does not!
The problem is that Visual Studio changed the encryption algorithm from TripleDES to AES256-CBC with Version 2017. I changed the encryption and decryption methods to this and it worked for my VS 2017 projects:
protected virtual void EncryptElement(XmlElement element, string password) { if (password == null) throw new InvalidPaswordException(); var rgbSalt = new byte[8]; new RNGCryptoServiceProvider().GetBytes(rgbSalt); var document = element.GetDocument();
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(password, rgbSalt, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
//AES.Padding = PaddingMode.None;
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
using (StreamWriter sw = new StreamWriter(cs))
sw.Write(element.OuterXml);
}
var array = ms.ToArray();
foreach (XmlNode childNode in element.ChildNodes)
element.RemoveChild(childNode);
element.InnerText = Convert.ToBase64String(array);
var saltAttribute = document.CreateAttribute("Salt", XmlHelpers.Schemas.SSIS);
saltAttribute.Value = Convert.ToBase64String(rgbSalt);
element.SetAttribute("Salt", XmlHelpers.Schemas.SSIS, Convert.ToBase64String(rgbSalt));
element.SetAttribute("IV", XmlHelpers.Schemas.SSIS, Convert.ToBase64String(AES.IV));
}
}
}
protected virtual void DecryptElement(XmlElement element, string password) { var algXmlAttributeNode = XmlHelpers.GetAttributeNode(element, "Algorithm"); if (!string.IsNullOrEmpty(algXmlAttributeNode?.Value)) {
var saltXmlAttributeNode = XmlHelpers.GetAttributeNode(element, "Salt");
if (string.IsNullOrEmpty(saltXmlAttributeNode?.Value))
{
throw new InvalidXmlException($"Encrypted element {element.Name} does not contain required Attribute \"Salt\", or its contents is empty", element);
}
byte[] rgbSalt;
try
{
rgbSalt = Convert.FromBase64String(saltXmlAttributeNode.Value);
}
catch (FormatException)
{
throw new InvalidXmlException($"Invalid value of Attribute \"Salt\" ({saltXmlAttributeNode.Value}) in encrypted element {element.Name}", element);
}
var ivXmlAttributeNode = XmlHelpers.GetAttributeNode(element, "IV");
if (string.IsNullOrEmpty(ivXmlAttributeNode?.Value))
{
throw new InvalidXmlException($"Encrypted element {element.Name} does not contain required Attribute \"IV\", or its contents is empty", element);
}
byte[] iv;
try
{
iv = Convert.FromBase64String(ivXmlAttributeNode.Value);
}
catch (FormatException)
{
throw new InvalidXmlException($"Invalid value of Attribute \"IV\" ({ivXmlAttributeNode.Value}) in encrypted element {element.Name} ", element);
}
string xml;
byte[] buffer;
try
{
buffer = Convert.FromBase64String(element.InnerText);
}
catch (FormatException)
{
throw new InvalidXmlException($"Invalid value of encrypted element {element.Name}.", element);
}
try
{
using (MemoryStream ms = new MemoryStream(buffer))
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(password, rgbSalt, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = iv;
AES.Mode = CipherMode.CBC;
using (CryptoStream csDecrypt = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
xml = srDecrypt.ReadToEnd();
}
}
}
}
catch (CryptographicException)
{
throw new InvalidPaswordException();
}
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xml);
// The reason to not simply import the new node is because namespace declaration will also be imported with the node.
element.Attributes.Remove(saltXmlAttributeNode);
element.Attributes.Remove(ivXmlAttributeNode);
foreach (XmlNode childNode in element.ChildNodes)
element.RemoveChild(childNode);
element.InnerXml = xmlDocument.DocumentElement?.InnerXml;
}
}