| 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); | |
| } | |
| } | |
| } | |
| } |