|  | using OfficeOpenXml.Utils; | 
|  | using System; | 
|  | using System.Collections.Generic; | 
|  | using System.Globalization; | 
|  | using System.Linq; | 
|  | using System.Security.Cryptography; | 
|  | using System.Text; | 
|  | using System.Xml; | 
|  |  | 
|  | namespace OfficeOpenXml | 
|  | { | 
|  | /// <summary> | 
|  | /// Algorithm for password hash | 
|  | /// </summary> | 
|  | internal enum eProtectedRangeAlgorithm | 
|  | { | 
|  | /// <summary> | 
|  | /// Specifies that the MD2 algorithm, as defined by RFC 1319, shall be used. | 
|  | /// </summary> | 
|  | MD2, | 
|  | /// <summary> | 
|  | /// Specifies that the MD4 algorithm, as defined by RFC 1319, shall be used. | 
|  | /// </summary> | 
|  | MD4, | 
|  | /// <summary> | 
|  | /// Specifies that the MD5 algorithm, as defined by RFC 1319, shall be used. | 
|  | /// </summary> | 
|  | MD5, | 
|  | /// <summary> | 
|  | /// Specifies that the RIPEMD-128 algorithm, as defined by RFC 1319, shall be used. | 
|  | /// </summary> | 
|  | RIPEMD128, | 
|  | /// <summary> | 
|  | /// Specifies that the RIPEMD-160 algorithm, as defined by ISO/IEC10118-3:2004 shall be used. | 
|  | /// </summary> | 
|  | RIPEMD160, | 
|  | /// <summary> | 
|  | /// Specifies that the SHA-1 algorithm, as defined by ISO/IEC 10118-3:2004 shall be used. | 
|  | /// </summary> | 
|  | SHA1, | 
|  | /// <summary> | 
|  | /// Specifies that the SHA-256 algorithm, as defined by ISO/IEC10118-3:2004 shall be used. | 
|  | /// </summary> | 
|  | SHA256, | 
|  | /// <summary> | 
|  | /// Specifies that the SHA-384 algorithm, as defined by ISO/IEC 10118-3:2004 shall be used. | 
|  | /// </summary> | 
|  | SHA384, | 
|  | /// <summary> | 
|  | /// Specifies that the SHA-512 algorithm, as defined by ISO/IEC10118-3:2004 shall be used. | 
|  | /// </summary> | 
|  | SHA512, | 
|  | /// <summary> | 
|  | /// Specifies that the WHIRLPOOL algorithm, as defined by ISO/IEC 10118-3:2004 shall be used. | 
|  | /// </summary> | 
|  | WHIRLPOOL | 
|  | } | 
|  | public class ExcelProtectedRange : XmlHelper | 
|  | { | 
|  | public string Name | 
|  | { | 
|  | get | 
|  | { | 
|  | return GetXmlNodeString("@name"); | 
|  | } | 
|  | set | 
|  | { | 
|  | SetXmlNodeString("@name",value); | 
|  | } | 
|  | } | 
|  | ExcelAddress _address=null; | 
|  | public ExcelAddress Address | 
|  | { | 
|  | get | 
|  | { | 
|  | if(_address==null) | 
|  | { | 
|  | _address=new ExcelAddress(GetXmlNodeString("@sqref")); | 
|  | } | 
|  | return _address; | 
|  | } | 
|  | set | 
|  | { | 
|  | SetXmlNodeString("@sqref", SqRefUtility.ToSqRefAddress(value.Address)); | 
|  | _address=value; | 
|  | } | 
|  | } | 
|  |  | 
|  | internal ExcelProtectedRange(string name, ExcelAddress address, XmlNamespaceManager ns, XmlNode topNode) : | 
|  | base(ns,topNode) | 
|  | { | 
|  | Name = name; | 
|  | Address = address; | 
|  | } | 
|  | /// <summary> | 
|  | /// Sets the password for the range | 
|  | /// </summary> | 
|  | /// <param name="password"></param> | 
|  | public void SetPassword(string password) | 
|  | { | 
|  | var byPwd = Encoding.Unicode.GetBytes(password); | 
|  | var rnd = RandomNumberGenerator.Create(); | 
|  | var bySalt=new byte[16]; | 
|  | rnd.GetBytes(bySalt); | 
|  |  | 
|  | //Default SHA512 and 10000 spins | 
|  | Algorithm=eProtectedRangeAlgorithm.SHA512; | 
|  | SpinCount = SpinCount < 100000 ? 100000 : SpinCount; | 
|  |  | 
|  | //Combine salt and password and calculate the initial hash | 
|  | var hp=new SHA512CryptoServiceProvider(); | 
|  | var buffer=new byte[byPwd.Length + bySalt.Length]; | 
|  | Array.Copy(bySalt, buffer, bySalt.Length); | 
|  | Array.Copy(byPwd, 0, buffer, 16, byPwd.Length); | 
|  | var hash = hp.ComputeHash(buffer); | 
|  |  | 
|  | //Now iterate the number of spinns. | 
|  | for (var i = 0; i < SpinCount; i++) | 
|  | { | 
|  | buffer=new byte[hash.Length+4]; | 
|  | Array.Copy(hash, buffer, hash.Length); | 
|  | Array.Copy(BitConverter.GetBytes(i), 0, buffer, hash.Length, 4); | 
|  | hash = hp.ComputeHash(buffer); | 
|  | } | 
|  | Salt = Convert.ToBase64String(bySalt); | 
|  | Hash = Convert.ToBase64String(hash); | 
|  | } | 
|  | public string SecurityDescriptor | 
|  | { | 
|  | get | 
|  | { | 
|  | return GetXmlNodeString("@securityDescriptor"); | 
|  | } | 
|  | set | 
|  | { | 
|  | SetXmlNodeString("@securityDescriptor",value); | 
|  | } | 
|  | } | 
|  | internal int SpinCount | 
|  | { | 
|  | get | 
|  | { | 
|  | return GetXmlNodeInt("@spinCount"); | 
|  | } | 
|  | set | 
|  | { | 
|  | SetXmlNodeString("@spinCount",value.ToString(CultureInfo.InvariantCulture)); | 
|  | } | 
|  | } | 
|  | internal string Salt | 
|  | { | 
|  | get | 
|  | { | 
|  | return GetXmlNodeString("@saltValue"); | 
|  | } | 
|  | set | 
|  | { | 
|  | SetXmlNodeString("@saltValue", value); | 
|  | } | 
|  | } | 
|  | internal string Hash | 
|  | { | 
|  | get | 
|  | { | 
|  | return GetXmlNodeString("@hashValue"); | 
|  | } | 
|  | set | 
|  | { | 
|  | SetXmlNodeString("@hashValue", value); | 
|  | } | 
|  | } | 
|  | internal eProtectedRangeAlgorithm Algorithm | 
|  | { | 
|  | get | 
|  | { | 
|  | var v=GetXmlNodeString("@algorithmName"); | 
|  | return (eProtectedRangeAlgorithm)Enum.Parse(typeof(eProtectedRangeAlgorithm), v.Replace("-", "")); | 
|  | } | 
|  | set | 
|  | { | 
|  | var v = value.ToString(); | 
|  | if(v.StartsWith("SHA")) | 
|  | { | 
|  | v=v.Insert(3,"-"); | 
|  | } | 
|  | else if(v.StartsWith("RIPEMD")) | 
|  | { | 
|  | v=v.Insert(6,"-"); | 
|  | } | 
|  | SetXmlNodeString("@algorithmName", v); | 
|  | } | 
|  | } | 
|  | } | 
|  | } |