Пример #1
0
        /// <summary>
        /// Load an authenticator from a Stream with an explicit password for this current version
        /// </summary>
        /// <param name="stream">Stream to read</param>
        /// <param name="password">explicit password if requried</param>
        /// <param name="version">expected version of authenticator</param>
        /// <returns>loaded Authenticator</returns>
        public static Authenticator ReadFromStream(Stream stream, string password, decimal version)
        {
            using (XmlReader xr = XmlReader.Create(stream))
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(xr);
                XmlNode rootnode = doc.DocumentElement;
                XmlNode node;

                Authenticator authenticator = null;

                // get the type is we have it, else use the default
                XmlAttribute authenticatorType = rootnode.Attributes["type"];
                if (authenticatorType != null)
                {
                    Type type = System.Reflection.Assembly.GetExecutingAssembly().GetType(authenticatorType.Value, false, true);
                    authenticator = Activator.CreateInstance(type) as Authenticator;
                }
                if (authenticator == null)
                {
                    authenticator = new BattleNetAuthenticator();
                }

                // is the Mobile Authenticator file? <xml.../><map>...</map>
                node = rootnode.SelectSingleNode("/map/string[@name='" + BMA_HASH_NAME + "']");
                if (node != null)
                {
                    string data = node.InnerText;

                    // extract the secret key and serial
                    byte[] bytes = StringToByteArray(data);
                    // decrpyt with the fixed key
                    for (int i = bytes.Length - 1; i >= 0; i--)
                    {
                        bytes[i] ^= MOBILE_AUTHENTICATOR_KEY[i];
                    }
                    // decode and set members
                    string full = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
                    authenticator.SecretData = full;

                    // get offset value
                    long offset = 0;
                    node = rootnode.SelectSingleNode("/map/long[@name='" + BMA_OFFSET_NAME + "']");
                    if (node != null && LongTryParse(node.Attributes["value"].InnerText, out offset) /* long.TryParse(node.Attributes["value"].InnerText, out offset) == true */)
                    {
                        authenticator.ServerTimeDiff = offset;
                    }

                    return(authenticator);
                }

                // read <= 1.6 config
                if (version <= (decimal)1.6 && (node = rootnode.SelectSingleNode("secretdata")) != null)
                {
                    // save off the processed decryptions so we can send bug report
                    List <string> datas = new List <string>();
                    string        data  = node.InnerText;
                    datas.Add(data);

                    XmlAttribute attr = node.Attributes["encrypted"];
                    if (attr != null && attr.InnerText.Length != 0)
                    {
                        string encryptedType = attr.InnerText;
                        if (encryptedType == "u")
                        {
                            // we are going to decrypt with the Windows User account key
                            authenticator.PasswordType = PasswordTypes.User;
                            byte[] cipher = StringToByteArray(data);
                            byte[] plain  = ProtectedData.Unprotect(cipher, null, DataProtectionScope.CurrentUser);
                            data = ByteArrayToString(plain);
                            datas.Add(data);
                        }
                        else if (encryptedType == "m")
                        {
                            // we are going to decrypt with the Windows local machine key
                            authenticator.PasswordType = PasswordTypes.Machine;
                            byte[] cipher = StringToByteArray(data);
                            byte[] plain  = ProtectedData.Unprotect(cipher, null, DataProtectionScope.LocalMachine);
                            data = ByteArrayToString(plain);
                            datas.Add(data);
                        }
                        else if (encryptedType == "y")
                        {
                            // we use an explicit password to encrypt data
                            if (string.IsNullOrEmpty(password) == true)
                            {
                                throw new EncrpytedSecretDataException();
                            }
                            authenticator.PasswordType = PasswordTypes.Explicit;
                            authenticator.Password     = password;
                            data = Decrypt(data, password, false);
                            datas.Add(data);
                        }
                    }
                    try
                    {
                        authenticator.SecretData = ConvertAndriodSecretData(data);
                    }
                    catch (Exception ex)
                    {
                        // we get a decode error if the data decrypted but isn't valid
                        throw new InvalidSecretDataException(ex, password, (attr != null ? attr.InnerText : null), datas);
                    }

                    long offset = 0;
                    node = rootnode.SelectSingleNode("servertimediff");
                    if (node != null && LongTryParse(node.InnerText, out offset) == true /* long.TryParse(node.InnerText, out offset) == true */)
                    {
                        authenticator.ServerTimeDiff = offset;
                    }

                    node = rootnode.SelectSingleNode("restorecodeverified");
                    if (node != null && string.Compare(node.InnerText, bool.TrueString.ToLower(), true) == 0)
                    {
                        authenticator.RestoreCodeVerified = true;
                    }

                    return(authenticator);
                }

                // read current config
                if ((node = rootnode.SelectSingleNode("secretdata")) != null)
                {
                    // save off the processed decryptions so we can send bug report
                    string        data  = node.InnerText;
                    XmlAttribute  attr  = node.Attributes["encrypted"];
                    List <string> datas = new List <string>();
                    datas.Add(data);
                    PasswordTypes passwordType = PasswordTypes.None;
                    if (attr != null && attr.InnerText.Length != 0)
                    {
                        char[] encTypes = attr.InnerText.ToCharArray();
                        // we read the string in reverse order (the order they were encrypted)
                        for (int i = encTypes.Length - 1; i >= 0; i--)
                        {
                            char encryptedType = encTypes[i];
                            switch (encryptedType)
                            {
                            case 'u':
                            {
                                // we are going to decrypt with the Windows User account key
                                try
                                {
                                    passwordType |= PasswordTypes.User;
                                    byte[] cipher = StringToByteArray(data);
                                    byte[] plain  = ProtectedData.Unprotect(cipher, null, DataProtectionScope.CurrentUser);
                                    data = ByteArrayToString(plain);
                                    datas.Add(data);
                                }
                                catch (System.Security.Cryptography.CryptographicException)
                                {
                                    throw new InvalidUserDecryptionException();
                                }
                                break;
                            }

                            case 'm':
                            {
                                // we are going to decrypt with the Windows local machine key
                                try
                                {
                                    passwordType |= PasswordTypes.Machine;
                                    byte[] cipher = StringToByteArray(data);
                                    byte[] plain  = ProtectedData.Unprotect(cipher, null, DataProtectionScope.LocalMachine);
                                    data = ByteArrayToString(plain);
                                    datas.Add(data);
                                }
                                catch (System.Security.Cryptography.CryptographicException)
                                {
                                    throw new InvalidMachineDecryptionException();
                                }
                                break;
                            }

                            case 'y':
                            {
                                // we use an explicit password to encrypt data
                                if (string.IsNullOrEmpty(password) == true)
                                {
                                    throw new EncrpytedSecretDataException();
                                }
                                passwordType          |= PasswordTypes.Explicit;
                                authenticator.Password = password;
                                data = Decrypt(data, password, true);
                                datas.Add(data);
                                break;
                            }

                            default:
                                break;
                            }
                        }
                        authenticator.PasswordType = passwordType;
                    }
                    try
                    {
                        // pre-version 2 we kept compatability with the Android file
                        if (version < (decimal)2)
                        {
                            data = ConvertAndriodSecretData(data);
                        }
                        authenticator.SecretData = data;
                    }
                    catch (Exception ex)
                    {
                        throw new InvalidSecretDataException(ex, password, (attr != null ? attr.InnerText : null), datas);
                    }

                    long offset = 0;
                    node = rootnode.SelectSingleNode("servertimediff");
                    if (node != null && LongTryParse(node.InnerText, out offset) == true /* long.TryParse(node.InnerText, out offset) == true */)
                    {
                        authenticator.ServerTimeDiff = offset;
                    }

                    node = rootnode.SelectSingleNode("restorecodeverified");
                    if (node != null && string.Compare(node.InnerText, bool.TrueString.ToLower(), true) == 0)
                    {
                        authenticator.RestoreCodeVerified = true;
                    }

                    return(authenticator);
                }

                throw new InvalidOperationException();
            }
        }
Пример #2
0
        /// <summary>
        /// Load an authenticator from a Stream with an explicit password for this current version
        /// </summary>
        /// <param name="stream">Stream to read</param>
        /// <param name="password">explicit password if requried</param>
        /// <param name="version">expected version of authenticator</param>
        /// <returns>loaded Authenticator</returns>
        public static Authenticator ReadFromStream(Stream stream, string password, decimal version)
        {
            using (XmlReader xr = XmlReader.Create(stream))
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(xr);
                XmlNode rootnode = doc.DocumentElement;
                XmlNode node;

                Authenticator authenticator = null;

                // get the type is we have it, else use the default
                XmlAttribute authenticatorType = rootnode.Attributes["type"];
                if (authenticatorType != null)
                {
                    Type type = System.Reflection.Assembly.GetExecutingAssembly().GetType(authenticatorType.Value, false, true);
                    authenticator = Activator.CreateInstance(type) as Authenticator;
                }
                if (authenticator == null)
                {
                    authenticator = new BattleNetAuthenticator();
                }

                // is the Mobile Authenticator file? <xml.../><map>...</map>
                node = rootnode.SelectSingleNode("/map/string[@name='" + BMA_HASH_NAME + "']");
                if (node != null)
                {
                    string data = node.InnerText;

                    // extract the secret key and serial
                    byte[] bytes = StringToByteArray(data);
                    // decrpyt with the fixed key
                    for (int i = bytes.Length - 1; i >= 0; i--)
                    {
                        bytes[i] ^= MOBILE_AUTHENTICATOR_KEY[i];
                    }
                    // decode and set members
                    string full = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
                    authenticator.SecretData = full;

                    // get offset value
                    long offset = 0;
                    node = rootnode.SelectSingleNode("/map/long[@name='" + BMA_OFFSET_NAME + "']");
                    if (node != null && LongTryParse(node.Attributes["value"].InnerText, out offset) /* long.TryParse(node.Attributes["value"].InnerText, out offset) == true */)
                    {
                        authenticator.ServerTimeDiff = offset;
                    }

                    return authenticator;
                }

                // read <= 1.6 config
                if (version <= (decimal)1.6 && (node = rootnode.SelectSingleNode("secretdata")) != null)
                {
                    // save off the processed decryptions so we can send bug report
                    List<string> datas = new List<string>();
                    string data = node.InnerText;
                    datas.Add(data);

                    XmlAttribute attr = node.Attributes["encrypted"];
                    if (attr != null && attr.InnerText.Length != 0)
                    {
                        string encryptedType = attr.InnerText;
                        if (encryptedType == "u")
                        {
                            // we are going to decrypt with the Windows User account key
                            authenticator.PasswordType = PasswordTypes.User;
                            byte[] cipher = StringToByteArray(data);
                            byte[] plain = ProtectedData.Unprotect(cipher, null, DataProtectionScope.CurrentUser);
                            data = ByteArrayToString(plain);
                            datas.Add(data);
                        }
                        else if (encryptedType == "m")
                        {
                            // we are going to decrypt with the Windows local machine key
                            authenticator.PasswordType = PasswordTypes.Machine;
                            byte[] cipher = StringToByteArray(data);
                            byte[] plain = ProtectedData.Unprotect(cipher, null, DataProtectionScope.LocalMachine);
                            data = ByteArrayToString(plain);
                            datas.Add(data);
                        }
                        else if (encryptedType == "y")
                        {
                            // we use an explicit password to encrypt data
                            if (string.IsNullOrEmpty(password) == true)
                            {
                                throw new EncrpytedSecretDataException();
                            }
                            authenticator.PasswordType = PasswordTypes.Explicit;
                            authenticator.Password = password;
                            data = Decrypt(data, password, false);
                            datas.Add(data);
                        }
                    }
                    try
                    {
                        authenticator.SecretData = ConvertAndriodSecretData(data);
                    }
                    catch (Exception ex)
                    {
                        // we get a decode error if the data decrypted but isn't valid
                        throw new InvalidSecretDataException(ex, password, (attr != null ? attr.InnerText : null), datas);
                    }

                    long offset = 0;
                    node = rootnode.SelectSingleNode("servertimediff");
                    if (node != null && LongTryParse(node.InnerText, out offset) == true /* long.TryParse(node.InnerText, out offset) == true */)
                    {
                        authenticator.ServerTimeDiff = offset;
                    }

                    node = rootnode.SelectSingleNode("restorecodeverified");
                    if (node != null && string.Compare(node.InnerText, bool.TrueString.ToLower(), true) == 0)
                    {
                        authenticator.RestoreCodeVerified = true;
                    }

                    return authenticator;
                }

                // read current config
                if ((node = rootnode.SelectSingleNode("secretdata")) != null)
                {
                    // save off the processed decryptions so we can send bug report
                    string data = node.InnerText;
                    XmlAttribute attr = node.Attributes["encrypted"];
                    List<string> datas = new List<string>();
                    datas.Add(data);
                    PasswordTypes passwordType = PasswordTypes.None;
                    if (attr != null && attr.InnerText.Length != 0)
                    {
                        char[] encTypes = attr.InnerText.ToCharArray();
                        // we read the string in reverse order (the order they were encrypted)
                        for (int i = encTypes.Length - 1; i >= 0; i--)
                        {
                            char encryptedType = encTypes[i];
                            switch (encryptedType)
                            {
                                case 'u':
                                    {
                                        // we are going to decrypt with the Windows User account key
                                        try
                                        {
                                            passwordType |= PasswordTypes.User;
                                            byte[] cipher = StringToByteArray(data);
                                            byte[] plain = ProtectedData.Unprotect(cipher, null, DataProtectionScope.CurrentUser);
                                            data = ByteArrayToString(plain);
                                            datas.Add(data);
                                        }
                                        catch (System.Security.Cryptography.CryptographicException)
                                        {
                                            throw new InvalidUserDecryptionException();
                                        }
                                        break;
                                    }
                                case 'm':
                                    {
                                        // we are going to decrypt with the Windows local machine key
                                        try
                                        {
                                            passwordType |= PasswordTypes.Machine;
                                            byte[] cipher = StringToByteArray(data);
                                            byte[] plain = ProtectedData.Unprotect(cipher, null, DataProtectionScope.LocalMachine);
                                            data = ByteArrayToString(plain);
                                            datas.Add(data);
                                        }
                                        catch (System.Security.Cryptography.CryptographicException)
                                        {
                                            throw new InvalidMachineDecryptionException();
                                        }
                                        break;
                                    }
                                case 'y':
                                    {
                                        // we use an explicit password to encrypt data
                                        if (string.IsNullOrEmpty(password) == true)
                                        {
                                            throw new EncrpytedSecretDataException();
                                        }
                                        passwordType |= PasswordTypes.Explicit;
                                        authenticator.Password = password;
                                        data = Decrypt(data, password, true);
                                        datas.Add(data);
                                        break;
                                    }
                                default:
                                    break;
                            }
                        }
                        authenticator.PasswordType = passwordType;
                    }
                    try
                    {
                        // pre-version 2 we kept compatability with the Android file
                        if (version < (decimal)2)
                        {
                            data = ConvertAndriodSecretData(data);
                        }
                        authenticator.SecretData = data;
                    }
                    catch (Exception ex)
                    {
                        throw new InvalidSecretDataException(ex, password, (attr != null ? attr.InnerText : null), datas);
                    }

                    long offset = 0;
                    node = rootnode.SelectSingleNode("servertimediff");
                    if (node != null && LongTryParse(node.InnerText, out offset) == true /* long.TryParse(node.InnerText, out offset) == true */)
                    {
                        authenticator.ServerTimeDiff = offset;
                    }

                    node = rootnode.SelectSingleNode("restorecodeverified");
                    if (node != null && string.Compare(node.InnerText, bool.TrueString.ToLower(), true) == 0)
                    {
                        authenticator.RestoreCodeVerified = true;
                    }

                    return authenticator;
                }

                throw new InvalidOperationException();
            }
        }