using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ChoiceMSLConnect { /// /// This class is copied (Stripped down to it's core, with all unneccessary stuff for this instance removed) /// from Registration Server's SystemAccessVerifier. /// All new code should go there. No Pin is generated here. The pin for a userkey /// should always be generated at the registration server. /// This class however can be used to convert a SystemApiKey to a UserApiKey, usefull for what we are /// trying to do in this service /// internal class SystemAccessVerifier { #region Consts const int SYSTEM_API_KEY_LENGTH = 22; const int USER_API_KEY_LENGTH = 20; const int PIN_LENGTH = 6; const string SYSTEM_API_KEY_BEGIN_MARKER = "$"; const string SYSTEM_API_KEY_END_MARKER = "#"; internal static readonly string LETTER_CHARS = "AZXVGLTCIRKPNOMQJSHUFWDEYB"; internal static int GET_LETTER_CHARS_COUNT { get { return LETTER_CHARS.Length; } } #endregion #region System Api Key private string _systemApiKey = String.Empty; internal string SystemApiKey { get { return _systemApiKey; } set { if (ValidateSystemKey(value)) _systemApiKey = value.ToUpper().Trim(); } } private static bool ValidateSystemKey(string key) { if (!String.IsNullOrEmpty(key)) key = key.ToUpper().Trim(); // $247B2CB4A437EB74C62#M if (!String.IsNullOrEmpty(key) && key.Length == SYSTEM_API_KEY_LENGTH && key[0] == Char.Parse(SYSTEM_API_KEY_BEGIN_MARKER) && key[SYSTEM_API_KEY_LENGTH - 2] == Char.Parse(SYSTEM_API_KEY_END_MARKER) && Char.IsLetter(key[SYSTEM_API_KEY_LENGTH - 1])) { // AllAreLettersOrDigit? for (int i = 1; i < SYSTEM_API_KEY_LENGTH - 2; ++i) { if (!Char.IsLetterOrDigit(key[i])) return false; } return true; } return false; } #endregion #region User Api Key private string _UserApiKey = String.Empty; internal string UserApiKey { get { return _UserApiKey; } set { if (ValidateUserKey(value)) _UserApiKey = value.ToUpper().Trim(); } } private static bool ValidateUserKey(string key) { if (!String.IsNullOrEmpty(key)) key = key.ToUpper().Trim(); //247BQCB4A-37EB-4C62M if (!String.IsNullOrEmpty(key) && key.Length == USER_API_KEY_LENGTH && Char.IsLetter(key[USER_API_KEY_LENGTH - 1]) && Char.IsLetter(key[4]) && key[9] == '-' && key[14] == '-') { // Perform Product Security check char productType = key[USER_API_KEY_LENGTH - 1]; int v = (int)productType % GET_LETTER_CHARS_COUNT; if (key[4] == LETTER_CHARS[v]) return true; } return false; } #endregion #region Product Type private char _productType = '\0'; internal char ProductType { get { return Char.ToUpper(_productType); } } internal bool IsValidProductType { get { return (_productType != '\0'); } } #endregion #region Construction internal SystemAccessVerifier(string userApiKey) { if (!String.IsNullOrEmpty(userApiKey)) userApiKey = userApiKey.ToUpper().Trim(); if (ValidateUserKey(userApiKey)) { UserApiKey = userApiKey; ConvertUserToSystemApiKey(); _productType = GetProductTypeFromSystemApiKey(SystemApiKey); } } #endregion #region Private Converters private void ConvertUserToSystemApiKey() { if (ValidateUserKey(UserApiKey)) { // 247BQCB4A-37EB-4C62M StringBuilder sb = new StringBuilder(UserApiKey); char productType = sb[USER_API_KEY_LENGTH - 1]; sb.Remove(USER_API_KEY_LENGTH - 1, 1); // Add More Randomness into this (nobody will ever know :S) // Dynamic Calc for 2 - 2, 12 - 4 int a = (int)'A'; int z = (int)'Z'; int ic = (int)sb[2]; if ((ic - 2 >= a) && (ic <= z)) sb[2] = (char)(ic - 2); ic = sb[12]; if ((ic - 4 >= a) && (ic <= z)) sb[12] = (char)(ic - 4); //Otherway arround arbitrary swap (just in case) // Swap 3 to 10, and 5 to 16 char c = sb[3]; sb[3] = sb[10]; sb[10] = c; c = sb[5]; sb[5] = sb[16]; sb[16] = c; // Assign '-' sb[4] = '-'; // How clever :S string s = ReverseString(sb.ToString()); int n = 0; sb = new StringBuilder(s); for (int i = 0; i < s.Length; ++i) { if (s[i] == '-') { sb[i] = (s[n]); n++; } else { sb[i] = (s[i]); } } // $247B2CB4A437EB74C62#M s = SYSTEM_API_KEY_BEGIN_MARKER + sb.ToString() + SYSTEM_API_KEY_END_MARKER + Char.ToUpper(productType); SystemApiKey = s; } } #endregion #region Internal Statics internal static char GetProductTypeFromSystemApiKey(string systemApiKey) { if (ValidateSystemKey(systemApiKey)) return Char.ToUpper(systemApiKey[SYSTEM_API_KEY_LENGTH - 1]); else return '\0'; } #endregion #region Private static Key Generation Helper Functions private static string ReverseString(string str) { if (!String.IsNullOrEmpty(str)) { Stack stack = new Stack(); foreach (char c in str) stack.Push(c); StringBuilder sb = new StringBuilder(); while (stack.Count > 0) sb.Append(stack.Pop()); return sb.ToString(); } return String.Empty; } /// /// Perform checksum on string /// /// /// Checksum private static int PerformChecksum(string strAboutToBeChecksummed) { if (!String.IsNullOrEmpty(strAboutToBeChecksummed)) { int nChecksum = 0; for (int i = 0; i < strAboutToBeChecksummed.Length; ++i) { if (Char.IsDigit(strAboutToBeChecksummed[i])) nChecksum = nChecksum + int.Parse(strAboutToBeChecksummed[i].ToString()); } return nChecksum; } return 0; } /// /// Dash a String every Nth Character /// /// a dashed string private static string MakeIntoDashSeperatedString(string strAboutToBeDashed, int DashEveryNthCharacter) { if (!String.IsNullOrEmpty(strAboutToBeDashed)) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < strAboutToBeDashed.Length; i++) { if ((i != 0) && ((i % DashEveryNthCharacter) == 0)) sb.Append("-"); sb.Append(strAboutToBeDashed[i]); } return sb.ToString(); } return String.Empty; } /// /// Undash a String /// /// a string without dashes private static string MakeIntoDashUnseperatedString(string strAboutToBeUndashed) { if (!String.IsNullOrEmpty(strAboutToBeUndashed)) return strAboutToBeUndashed.Replace("-", ""); return String.Empty; } /// /// Check if the passed in string contains only digits /// /// string to check for digits for /// true, if all digits are numbers private static bool ContainsOnlyDigits(string strToCheckForDigits) { if (!String.IsNullOrEmpty(strToCheckForDigits)) { for (int i = 0; i < strToCheckForDigits.Length; ++i) { if (!Char.IsDigit(strToCheckForDigits[i])) return false; } return true; } return false; } #endregion } }