/// <summary> /// /// </summary> /// <param name="signature"></param> /// <returns></returns> /// <exception cref="BaseSignatureVerificationException"></exception> private Dictionary <string, Object> Parse3(string signature) { signature = SignatureVerifierUtils.FromBase64(signature); if (!"".Equals(signature)) { throw new SignatureVerificationException("invalid base64 payload"); } UnpackResult unpackResult = Unpacker.Unpack( "Cversion/NrequestTime/NsignatureTime/CmasterSignType/nmasterTokenLength", signature); int version = (int)unpackResult.Data["version"]; if (version != 3) { throw new SignatureRangeException("unsupported version"); } long timestamp = (long)unpackResult.Data["timestamp"]; if (timestamp > (SignatureVerifierUtils.UnixTimestamp / 1000)) { throw new SignatureVerificationException("invalid timestamp (future time)"); } int masterTokenLength = (int)unpackResult.Data["masterTokenLength"]; string masterToken = SignatureVerifierUtils.Substr(signature, 12, masterTokenLength + 12); unpackResult.Data.Add("masterToken", masterToken); int s1, s2; if ((s1 = masterTokenLength) != (s2 = masterToken.Length)) { throw new SignatureVerificationException( string.Format("master token length mismatch ({0} / {1})", s1, s2)); } signature = SignatureVerifierUtils.Substr(signature, masterTokenLength + 12); Dictionary <string, Object> data2 = Unpacker.Unpack("CcustomerSignType/ncustomerTokenLength", signature).Data; int customerTokenLength = (int)data2["customerTokenLength"]; string customerToken = SignatureVerifierUtils.Substr(signature, 3, customerTokenLength + 3); data2.Add("customerToken", customerToken); if ((s1 = customerTokenLength) != (s2 = customerToken.Length)) { throw new SignatureVerificationException( string.Format("customer token length mismatch ({0} / {1})')", s1, s2)); } return(unpackResult.Data.Union(data2).ToDictionary(k => k.Key, v => v.Value)); }
private Field FieldTypeDef(int fieldId, int i) { if (_fieldIds.TryGetValue(fieldId, out var value)) { return(value); } string resultType = _fieldIds[fieldId & 0xC0].Type; string iStr = SignatureVerifierUtils.PadStart(i.ToString(), 2, '0'); string resultName = resultType + iStr; return(new Field(resultName, resultType)); }
internal SignatureVerificationResult VerifySignature( string signature, string userAgent, string signRole, string key, bool isKeyBase64Encoded, int?expiry, string[] ipAddresses) { SignatureVerificationResult validationResult = new SignatureVerificationResult(); try { key = isKeyBase64Encoded ? SignatureVerifierUtils.KeyDecode(key) : key; Dictionary <string, Object> data; try { data = Parse4(signature); } catch (BaseSignatureVerificationException exp) { if (exp is SignatureRangeException) { data = Parse3(signature); } else { validationResult.Error = exp.Message; return(validationResult); } } data.TryGetValue(signRole + "Token", out var signRoleTokenObj); string signRoleToken = (string)signRoleTokenObj; if (signRoleToken == null || signRoleToken.Length == 0) { validationResult.Error = "sign role signature mismatch"; return(validationResult); } int signType = SignatureVerifierUtils.CharacterToInt(data[signRole + "SignType"]); foreach (var ipAddress in ipAddresses) { string currentIpAddress = ipAddress; string token; if (currentIpAddress == null || currentIpAddress.Length == 0) { continue; } if (IpV6Utils.Validate(currentIpAddress)) { if (!data.ContainsKey(signRole + "TokenV6")) { continue; } token = (string)data[signRole + "TokenV6"]; currentIpAddress = IpV6Utils.Abbreviate(currentIpAddress); } else { if (!data.ContainsKey(signRole + "Token")) { continue; } token = (string)data[signRole + "Token"]; } int signatureTime = SignatureVerifierUtils.CharacterToInt(data["signatureTime"]); int requestTime = SignatureVerifierUtils.CharacterToInt(data["requestTime"]); foreach (string result in _results.Keys) { switch (signType) { case 1: string signatureBase = GetBase(result, requestTime, signatureTime, currentIpAddress, userAgent); bool isHashedDataEqualToToken = SignatureVerifierUtils.CompareBytes(SignatureVerifierUtils.Encode(key, signatureBase), token); if (isHashedDataEqualToToken) { if (IsExpired(expiry, signatureTime, requestTime)) { validationResult.Expired = true; return(validationResult); } validationResult.Score = int.Parse(result); validationResult.Verdict = _results[result.ToString()]; validationResult.IpAddress = currentIpAddress; validationResult.RequestTime = int.Parse(data["requestTime"].ToString()); validationResult.SignatureTime = int.Parse(data["signatureTime"].ToString()); return(validationResult); } break; case 2: validationResult.Error = "unsupported signature"; return(validationResult); default: validationResult.Error = "unrecognized signature"; return(validationResult); } } } validationResult.Error = "no verdict"; return(validationResult); } catch (Exception exp) { string base64Exception = "The input is not a valid Base-64 string"; if (exp.Message.StartsWith(base64Exception)) { validationResult.Error = exp.Message.Replace(base64Exception, "Key/Signature is not a valid Base-64 string"); return(validationResult); } else { validationResult.Error = exp.Message; return(validationResult); } } }
/// <summary> /// /// </summary> /// <param name="signature"></param> /// <returns></returns> /// <exception cref="BaseSignatureVerificationException"></exception> private Dictionary <string, Object> Parse4(string signature) { signature = SignatureVerifierUtils.FromBase64(signature); if (signature.Length == 0) { throw new SignatureVerificationException("invalid base64 payload"); } Dictionary <string, Object> data = Unpacker.Unpack("Cversion/CfieldNum", signature).Data; int version = SignatureVerifierUtils.CharacterToInt(data["version"]); if (version != 4) { throw new SignatureRangeException("unsupported version"); } signature = SignatureVerifierUtils.Substr(signature, 2); int fieldNum = SignatureVerifierUtils.CharacterToInt(data["fieldNum"]); for (int i = 0; i < fieldNum; ++i) { Dictionary <string, Object> header = Unpacker.Unpack("CfieldId", signature).Data; if (header.Count == 0 || !header.ContainsKey("fieldId")) // header.entrySet().size() ??? { throw new SignatureVerificationException("premature end of signature 0x01"); } Field fieldTypeDef = FieldTypeDef(SignatureVerifierUtils.CharacterToInt(header["fieldId"]), i); Dictionary <string, Object> v = new Dictionary <string, Object>(); Dictionary <string, Object> l; switch (fieldTypeDef.Type) { case "uchar": v = Unpacker.Unpack("Cx/Cv", signature).Data; if (v.ContainsKey("v")) { data.Add(fieldTypeDef.Name, v["v"]); } else { throw new SignatureVerificationException("premature end of signature 0x02"); } signature = SignatureVerifierUtils.Substr(signature, 2); break; case "ushort": v = Unpacker.Unpack("Cx/nv", signature).Data; if (v.ContainsKey("v")) { data.Add(fieldTypeDef.Name, v["v"]); } else { throw new Exception("premature end of signature 0x03"); } signature = SignatureVerifierUtils.Substr(signature, 3); break; case "ulong": v = Unpacker.Unpack("Cx/Nv", signature).Data; if (v.ContainsKey("v")) { data.Add(fieldTypeDef.Name, v["v"]); } else { throw new Exception("premature end of signature 0x04"); } signature = SignatureVerifierUtils.Substr(signature, 5); break; case "string": l = Unpacker.Unpack("Cx/nl", signature).Data; if (!l.ContainsKey("l")) { throw new Exception("premature end of signature 0x05"); } if ((SignatureVerifierUtils.CharacterToInt(l["l"]) & 0x8000) > 0) { int newl = SignatureVerifierUtils.CharacterToInt(l["l"]) & 0xFF; l.Add("l", newl); } string newV = SignatureVerifierUtils.Substr(signature, 3, SignatureVerifierUtils.CharacterToInt(l["l"])); v.Add("v", newV); data.Add(fieldTypeDef.Name, newV); if (((string)v["v"]).Length != SignatureVerifierUtils.CharacterToInt(l["l"])) { throw new SignatureVerificationException("premature end of signature 0x06"); } signature = SignatureVerifierUtils.Substr(signature, 3 + SignatureVerifierUtils.CharacterToInt(l["l"])); break; default: throw new SignatureVerificationException("unsupported variable type"); } } data.Remove(fieldNum.ToString()); return(data); }
internal static string Substr(string str, int length) { return(SignatureVerifierUtils.Substr(str, length, str.Length)); }
/// <summary> /// Unpacks data from a binary string into the respective format. /// </summary> /// <param name="format">fields that have to be unpacked from data, forward slash separated.</param> /// <param name="data">Binary string, already decoded from Base64</param> /// <returns>object which contains unpacked data as a hash map, where key is a name of /// the field. if result contains non-null error message then it means that unpacking failed. /// Data hash map is null then.</returns> /// <exception cref="SignatureVerificationException"></exception> internal static UnpackResult Unpack(string format, string data) { int formatPointer = 0; int dataPointer = 0; Dictionary <string, Object> resultMap = new Dictionary <string, Object>(); int instruction; string quantifier; int quantifierInt; string label; string currentData; int i; int currentResult; while (formatPointer < format.Length) { instruction = SignatureVerifierUtils.CharAt(format, formatPointer); quantifier = ""; formatPointer++; while ((formatPointer < format.Length) && SignatureVerifierUtils.IsCharMatches(@"\A(?:[\\d\\*])\z", SignatureVerifierUtils.CharAt(format, formatPointer))) { quantifier += SignatureVerifierUtils.CharAt(format, formatPointer); formatPointer++; } if (string.IsNullOrEmpty(quantifier)) { quantifier = "1"; } StringBuilder labelSb = new StringBuilder(); while ((formatPointer < format.Length) && (format[formatPointer] != '/')) { labelSb.Append(SignatureVerifierUtils.CharAt(format, formatPointer++)); } label = labelSb.ToString(); if (SignatureVerifierUtils.CharAt(format, formatPointer) == '/') { formatPointer++; } switch (instruction) { case 'c': case 'C': if ("*".Equals(quantifier)) { quantifierInt = data.Length - dataPointer; } else { quantifierInt = int.Parse(quantifier); } currentData = SignatureVerifierUtils.Substr(data, dataPointer, quantifierInt); dataPointer += quantifierInt; for (i = 0; i < currentData.Length; i++) { currentResult = SignatureVerifierUtils.CharAt(currentData, i); if ((instruction == 'c') && (currentResult >= 128)) { currentResult -= 256; } string key = label + (quantifierInt > 1 ? (i + 1).ToString() : ""); resultMap.Add(key, currentResult); } break; case 'n': if ("*".Equals(quantifier)) { quantifierInt = (data.Length - dataPointer) / 2; } else { quantifierInt = int.Parse(quantifier); } currentData = SignatureVerifierUtils.Substr(data, dataPointer, quantifierInt * 2); dataPointer += quantifierInt * 2; for (i = 0; i < currentData.Length; i += 2) { currentResult = (((SignatureVerifierUtils.CharAt(currentData, i) & 0xFF) << 8) + (SignatureVerifierUtils.CharAt(currentData, i + 1) & 0xFF)); string key = label + (quantifierInt > 1 ? ((i / 2) + 1).ToString() : ""); resultMap.Add(key, currentResult); } break; case 'N': if ("*".Equals(quantifier)) { quantifierInt = (data.Length - dataPointer) / 4; } else { quantifierInt = int.Parse(quantifier); } currentData = SignatureVerifierUtils.Substr(data, dataPointer, quantifierInt * 4); dataPointer += quantifierInt * 4; for (i = 0; i < currentData.Length; i += 4) { currentResult = (((SignatureVerifierUtils.CharAt(currentData, i) & 0xFF) << 24) + ((SignatureVerifierUtils.CharAt(currentData, i + 1) & 0xFF) << 16) + ((SignatureVerifierUtils.CharAt(currentData, i + 2) & 0xFF) << 8) + ((SignatureVerifierUtils.CharAt(currentData, i + 3) & 0xFF))); string key = label + (quantifierInt > 1 ? ((i / 4) + 1).ToString() : ""); resultMap.Add(key, currentResult); } break; default: return(new UnpackResult(string.Format("Unknown format code: {0}", instruction.ToString()))); } } return(new UnpackResult(resultMap));; }