/// <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));
 }
Beispiel #6
0
        /// <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));;
        }