using System; using System.Linq; using System.Text; using System.Security.Cryptography; using Jd.ACES.Common.Exceptions; namespace Jd.ACES.Common { public class IndexCalculator { readonly static string LONG_PLACEHOLDER; static IndexCalculator() { LONG_PLACEHOLDER = GeneratePlaceholderForNonAscii(); } /// /// Computes hash value for the specified input and salt with SHA256 algorithm. /// /// The byte array of input to compute. /// The byte array of salt to compute. /// The byte array of computed hash code. /// Thrown when input is null. /// Thrown when salt lenght is too short. public static byte[] Sha256Index(byte[] input, byte[] salt) { if (input == null) throw new ArgumentException("Input is null for sha256Index function."); if (salt == null || salt.Length < Constants.MIN_SALT_LEN) throw new InsufficientSaltLengthException("Salt length is too short."); byte[] combined = new byte[input.Length + salt.Length]; // append input and salt together Array.Copy(input, 0, combined, 0, input.Length); Array.Copy(salt, 0, combined, input.Length, salt.Length); using (SHA256 hash = SHA256.Create()) { return hash.ComputeHash(combined); } } static string GeneratePlaceholderForNonAscii() { StringBuilder buffer = new StringBuilder(); for (int i = 0; i < 6; i++) { buffer.Append(WildcardPattern.ASCII); } return buffer.ToString(); } /// /// Attempts to format the specified plaintext to unicode encoding. /// /// The original plaintext to format. /// formatted plaintext if the plaintext contains non-ASCII character. public static string FormatPlaintext(string plaintext) { return UnicodeEncode(plaintext); } /// /// Attempts to format the query keyword to unicode encoding. /// /// The original query keyword to format. /// formatted keyword. public static string FormatQueryKeyword(string keyword) { return FormatQueryKeyword(keyword, WildcardPattern.NON_ASCII); } /// /// Attempts to format the query keyword to unicode encoding. /// Each placeholder for non-ASCII character, such as '#', /// in keyword will be replaced with the long placeholder. /// /// The original query keyword to format. /// The placeholder for non-ASCII character. /// formatted keyword. public static string FormatQueryKeyword(string keyword, char placeholderForNonAscii) { keyword = UnicodeEncode(keyword); if (!keyword.Contains(placeholderForNonAscii)) { return keyword; } StringBuilder buffer = new StringBuilder(); for (int i = 0, len = keyword.Length; i < len; i++) { if (keyword[i] == placeholderForNonAscii) { buffer.Append(LONG_PLACEHOLDER); } else if (keyword[i] == WildcardPattern.ASCII) { buffer.Append(keyword[i]); } else { buffer.Append(keyword.Substring(i, keyword.Length - i)); break; } } return buffer.ToString(); } /// /// Encodes the specified non-ASCII string to unicode encoding. /// /// The string to encode. /// unicode encoding string. public static string UnicodeEncode(string data) { if (IsPureAscii(data)) return data; char[] utfBytes = data.ToCharArray(); StringBuilder buffer = new StringBuilder(); for (int byteIndex = 0, len = utfBytes.Length; byteIndex < len; byteIndex++) { if (IsPureAscii(utfBytes[byteIndex])) { buffer.Append(utfBytes[byteIndex]); continue; } buffer.Append("\\u").AppendFormat("{0:x2}", (int)utfBytes[byteIndex]); } return buffer.ToString(); } /// /// Decodes the specified unicode encoding string. /// /// The string to decode. /// decoded string. public static string UnicodeDecode(string data) { StringBuilder buffer = new StringBuilder(); string charStr = ""; for (int i = 0, len = data.Length; i < len;) { int offset = data.IndexOf("\\u", i); if (offset == -1 || offset + 6 > data.Length) { charStr = data.Substring(i, data.Length - i); buffer.Append(charStr); i = data.Length; } else { buffer.Append(data.Substring(i, offset - i)); charStr = data.Substring(offset + 2, 4); string letter = Char.ConvertFromUtf32(Convert.ToInt32(charStr, 16)); buffer.Append(letter); i = offset + 6; } } return buffer.ToString(); } public static bool IsPureAscii(char c) { return c >= 0 && c < 128; } public static bool IsPureAscii(string s) { return Encoding.UTF8.GetByteCount(s) == s.Length; } public static string GenerateWildcardKeyword(string keyword, int asciiCharPrefixNumber, int nonAsciiCharPrefixNumber) { int length = asciiCharPrefixNumber + nonAsciiCharPrefixNumber * 6; if (length == 0) { return keyword; } StringBuilder buffer = new StringBuilder(); char[] prefix = Enumerable.Repeat(WildcardPattern.ASCII, length).ToArray(); return buffer.Append(prefix).Append(keyword).ToString(); } } public class WildcardPattern { public static char ASCII { get { return '*'; } } public static char NON_ASCII { get { return '#'; } } } }