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