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