Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. Visual Basic
  4. Securing Local Files [Solved]

Securing Local Files [Solved]

Scheduled Pinned Locked Moved Visual Basic
securitycsharphelp
20 Posts 8 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Saul Johnson

    Hello, My VB.NET application currently securely downloads a username and password required to access a web service that contains sensitive data. The problem I face now is storing that username and password on-disk in a secure manner for future use. I've looked into various encryption algorithms etc. but all involve storing some kind of key for decryption locally (rendering the encryption a bit of a joke) or hard-coding the key into the application (difficult-to-maintain and just about as useful as the last option). I welcome any suggestions as to how relatively secure local storage of a username and password might be accomplished. Despite hours of wracking my brains poking about in the System.Security.Cryptography namespace I'm no closer to finding a solution than I was at the start. SixOfTheClock

    A programming language is to a programmer what a fine hat is to one who is fond of fancy garden parties. Just don't try wearing any .NET language on your head. Some of them are sharp.

    L Offline
    L Offline
    Lost User
    wrote on last edited by
    #3

    Simplest solution is to NOT store it locally. Store it on your (web)server, and have your app request it when required. (That's still no guarantee that no-one will duplicate the sensitive data btw)

    Bastard Programmer from Hell :suss: if you can't read my code, try converting it here[^]

    S 1 Reply Last reply
    0
    • A AspDotNetDev

      Not the answer you're going to want to hear, but it can't really be done. If you really want it to be secure, you'll have to require the user to enter a master password. Other popular programs do this too. Typically, you will be given the option of encrypting multiple passwords using one master password (most secure) or encrypting the passwords using a built-in key (which would be stored in plain text somewhere). You could also use multiple layers of indirection (e.g., a config setting that points to a file that stores the path the encryption key is stored in) to make it harder for somebody to obtain the encryption key, but it's not really any more secure (just harder to access).

      Thou mewling ill-breeding pignut!

      S Offline
      S Offline
      Saul Johnson
      wrote on last edited by
      #4

      Ah, I thought as much. I'll take a look into these options, thank you very much indeed! :D

      A programming language is to a programmer what a fine hat is to one who is fond of fancy garden parties. Just don't try wearing any .NET language on your head. Some of them are sharp.

      1 Reply Last reply
      0
      • L Lost User

        Simplest solution is to NOT store it locally. Store it on your (web)server, and have your app request it when required. (That's still no guarantee that no-one will duplicate the sensitive data btw)

        Bastard Programmer from Hell :suss: if you can't read my code, try converting it here[^]

        S Offline
        S Offline
        Saul Johnson
        wrote on last edited by
        #5

        Very sensible idea there, and very true about the sensitive data. If the point of my application is to search through and display said sensitive data then it would be impossible to completely secure for that very reason. Thank you for your reply, this seems like a better way to go about it and is well worth testing out. :D

        A programming language is to a programmer what a fine hat is to one who is fond of fancy garden parties. Just don't try wearing any .NET language on your head. Some of them are sharp.

        L 1 Reply Last reply
        0
        • S Saul Johnson

          Very sensible idea there, and very true about the sensitive data. If the point of my application is to search through and display said sensitive data then it would be impossible to completely secure for that very reason. Thank you for your reply, this seems like a better way to go about it and is well worth testing out. :D

          A programming language is to a programmer what a fine hat is to one who is fond of fancy garden parties. Just don't try wearing any .NET language on your head. Some of them are sharp.

          L Offline
          L Offline
          Lost User
          wrote on last edited by
          #6

          You're welcome :)

          1 Reply Last reply
          0
          • S Saul Johnson

            Hello, My VB.NET application currently securely downloads a username and password required to access a web service that contains sensitive data. The problem I face now is storing that username and password on-disk in a secure manner for future use. I've looked into various encryption algorithms etc. but all involve storing some kind of key for decryption locally (rendering the encryption a bit of a joke) or hard-coding the key into the application (difficult-to-maintain and just about as useful as the last option). I welcome any suggestions as to how relatively secure local storage of a username and password might be accomplished. Despite hours of wracking my brains poking about in the System.Security.Cryptography namespace I'm no closer to finding a solution than I was at the start. SixOfTheClock

            A programming language is to a programmer what a fine hat is to one who is fond of fancy garden parties. Just don't try wearing any .NET language on your head. Some of them are sharp.

            J Offline
            J Offline
            James H
            wrote on last edited by
            #7

            Whatever method you use I also like to have a set of "red herring" credentials - that looks likes a password, - e.g. config setting Password with some cyrptic looking string that could be an encrypted string - sends the b'rs of on a wild goose chase

            S 1 Reply Last reply
            0
            • S Saul Johnson

              Hello, My VB.NET application currently securely downloads a username and password required to access a web service that contains sensitive data. The problem I face now is storing that username and password on-disk in a secure manner for future use. I've looked into various encryption algorithms etc. but all involve storing some kind of key for decryption locally (rendering the encryption a bit of a joke) or hard-coding the key into the application (difficult-to-maintain and just about as useful as the last option). I welcome any suggestions as to how relatively secure local storage of a username and password might be accomplished. Despite hours of wracking my brains poking about in the System.Security.Cryptography namespace I'm no closer to finding a solution than I was at the start. SixOfTheClock

              A programming language is to a programmer what a fine hat is to one who is fond of fancy garden parties. Just don't try wearing any .NET language on your head. Some of them are sharp.

              S Offline
              S Offline
              Stephane Rivette At Motion
              wrote on last edited by
              #8

              Why not use Isolated storage, it's encrypted to the user and no one else using the computer can get to it. http://msdn.microsoft.com/en-us/library/3ak841sy%28v=VS.95%29.aspx[^]

              L 1 Reply Last reply
              0
              • A AspDotNetDev

                Not the answer you're going to want to hear, but it can't really be done. If you really want it to be secure, you'll have to require the user to enter a master password. Other popular programs do this too. Typically, you will be given the option of encrypting multiple passwords using one master password (most secure) or encrypting the passwords using a built-in key (which would be stored in plain text somewhere). You could also use multiple layers of indirection (e.g., a config setting that points to a file that stores the path the encryption key is stored in) to make it harder for somebody to obtain the encryption key, but it's not really any more secure (just harder to access).

                Thou mewling ill-breeding pignut!

                D Offline
                D Offline
                dcu lcr
                wrote on last edited by
                #9

                actually you can. The solution, however, is in using a .NET secure string for the password and store the secure string in a file. Take a look(bing it) at how to use secure strings with powershell, if you're using win 7 then it should be a piece of cake.

                L. Carlos Rodriguez DCU, LLC Braselton, GA 30517

                L 1 Reply Last reply
                0
                • S Stephane Rivette At Motion

                  Why not use Isolated storage, it's encrypted to the user and no one else using the computer can get to it. http://msdn.microsoft.com/en-us/library/3ak841sy%28v=VS.95%29.aspx[^]

                  L Offline
                  L Offline
                  Lost User
                  wrote on last edited by
                  #10

                  If the app can access it (required, otherwise it could not use the data), then so can I :)

                  Bastard Programmer from Hell :suss: if you can't read my code, try converting it here[^]

                  1 Reply Last reply
                  0
                  • D dcu lcr

                    actually you can. The solution, however, is in using a .NET secure string for the password and store the secure string in a file. Take a look(bing it) at how to use secure strings with powershell, if you're using win 7 then it should be a piece of cake.

                    L. Carlos Rodriguez DCU, LLC Braselton, GA 30517

                    L Offline
                    L Offline
                    Lost User
                    wrote on last edited by
                    #11

                    ..and there is me reading the file, and shouting your password in the streets. Any other solutions?

                    Bastard Programmer from Hell :suss: if you can't read my code, try converting it here[^]

                    D 1 Reply Last reply
                    0
                    • S Saul Johnson

                      Hello, My VB.NET application currently securely downloads a username and password required to access a web service that contains sensitive data. The problem I face now is storing that username and password on-disk in a secure manner for future use. I've looked into various encryption algorithms etc. but all involve storing some kind of key for decryption locally (rendering the encryption a bit of a joke) or hard-coding the key into the application (difficult-to-maintain and just about as useful as the last option). I welcome any suggestions as to how relatively secure local storage of a username and password might be accomplished. Despite hours of wracking my brains poking about in the System.Security.Cryptography namespace I'm no closer to finding a solution than I was at the start. SixOfTheClock

                      A programming language is to a programmer what a fine hat is to one who is fond of fancy garden parties. Just don't try wearing any .NET language on your head. Some of them are sharp.

                      B Offline
                      B Offline
                      BrainiacV
                      wrote on last edited by
                      #12

                      Not sure if this will help, Back in the early days of microcomputers, some publishers tried to encrypt their programs to keep them from being pirated. After you entered a key, a subroutine would be called to decrypt the code. The sneaky bit was that right after the subroutine call, there was additional code, but, the program never reached it. Part of the decryption overlaid the system stack and so the subroutine return went someplace else, rather than the legitimate looking code that followed the decryption. So I guess in a long winded way, I am suggesting the use of misdirection in addition to the indirection that has been suggested above. And then repeat. It won't stop them, but it could really slow them down.

                      Psychosis at 10 Film at 11 Those who do not remember the past, are doomed to repeat it. Those who do not remember the past, cannot build upon it.

                      S 1 Reply Last reply
                      0
                      • L Lost User

                        ..and there is me reading the file, and shouting your password in the streets. Any other solutions?

                        Bastard Programmer from Hell :suss: if you can't read my code, try converting it here[^]

                        D Offline
                        D Offline
                        dcu lcr
                        wrote on last edited by
                        #13

                        ...there's nothing better than making passwords public so you can shout them to the world, that's why we use the.NET secure string functionality for batch files protections at both the DOL and Treasury. But then again, this is the government and we don't know what we're doing.... :doh: Sorry I led you in the wrong path.... :(( Good luck

                        L 1 Reply Last reply
                        0
                        • D dcu lcr

                          ...there's nothing better than making passwords public so you can shout them to the world, that's why we use the.NET secure string functionality for batch files protections at both the DOL and Treasury. But then again, this is the government and we don't know what we're doing.... :doh: Sorry I led you in the wrong path.... :(( Good luck

                          L Offline
                          L Offline
                          Lost User
                          wrote on last edited by
                          #14

                          dcu.lcr wrote:

                          ...there's nothing better than making passwords public so you can shout them to the world, that's why we use the.NET secure string functionality for batch files protections at both the DOL and Treasury.

                          For batch files? :doh: Let me rephrase that; any secret that's stored, isn't.

                          dcu.lcr wrote:

                          But then again, this is the government and we don't know what we're doing.... :doh:

                          You working for the government is not an argument, nor does it validate your statement.

                          Bastard Programmer from Hell :suss: if you can't read my code, try converting it here[^]

                          1 Reply Last reply
                          0
                          • S Saul Johnson

                            Hello, My VB.NET application currently securely downloads a username and password required to access a web service that contains sensitive data. The problem I face now is storing that username and password on-disk in a secure manner for future use. I've looked into various encryption algorithms etc. but all involve storing some kind of key for decryption locally (rendering the encryption a bit of a joke) or hard-coding the key into the application (difficult-to-maintain and just about as useful as the last option). I welcome any suggestions as to how relatively secure local storage of a username and password might be accomplished. Despite hours of wracking my brains poking about in the System.Security.Cryptography namespace I'm no closer to finding a solution than I was at the start. SixOfTheClock

                            A programming language is to a programmer what a fine hat is to one who is fond of fancy garden parties. Just don't try wearing any .NET language on your head. Some of them are sharp.

                            O Offline
                            O Offline
                            ObiWan_MCC
                            wrote on last edited by
                            #15

                            I think you're approaching the issue the wrong way, see, you DON'T need to know the password (nor to store it); all you need to do is checking that it is correct For such a task, all you'll need will be using an MD5 "salted" hash; just to be clear, let's say you have the following code

                            // generates the unique (salted) hash of a string
                            private static string getKey(string sSalt, string sKey)
                            {
                            Byte[] originalBytes, encodedBytes;
                            MD5 hash = new MD5CryptoServiceProvider();
                            // or: SHA256 hash = new SHA256CryptoServiceProvider();

                            // generate the hash value
                            originalBytes = ASCIIEncoding.Default.GetBytes(sSalt + "." + sKey);
                            encodedBytes = hash.ComputeHash(originalBytes);
                            
                            // turn the hash to a string and return it
                            string sResult = BitConverter.ToString(encodedBytes).Replace("-", "");
                            // or: string sResult = Convert.ToBase64String(encodedBytes);
                            return sResult;
                            

                            }

                            now, in your login form, you ask to enter a username and a password, let's say you get back "jdoe" and "supersecret", at this point, you just call the above function this way

                            string hashValue = getKey(userName, userPass);

                            and the hashvalue will now contain something like "752dcc62c07fb4652981add596e1427b" now, with this value in your hands, you run a query on your database user table seeking for the user name (jdoe) and, if found, you compare the salted MD5 hash stored as the password with the one you just generated and, if they match, you grant access to the user. At this point, in case you need to use the password "in clear", you may just encrypt the password you received and store it into a session cookie, this will give you VOLATILE (temporary) storage and, while it will allow you to retrieve the password for the session lifetime, you won't in reality store the password anywhere on your server and... retrieving a password from a salted hash isn't exactly an easy task, believe me :) HTH

                            O S 2 Replies Last reply
                            0
                            • O ObiWan_MCC

                              I think you're approaching the issue the wrong way, see, you DON'T need to know the password (nor to store it); all you need to do is checking that it is correct For such a task, all you'll need will be using an MD5 "salted" hash; just to be clear, let's say you have the following code

                              // generates the unique (salted) hash of a string
                              private static string getKey(string sSalt, string sKey)
                              {
                              Byte[] originalBytes, encodedBytes;
                              MD5 hash = new MD5CryptoServiceProvider();
                              // or: SHA256 hash = new SHA256CryptoServiceProvider();

                              // generate the hash value
                              originalBytes = ASCIIEncoding.Default.GetBytes(sSalt + "." + sKey);
                              encodedBytes = hash.ComputeHash(originalBytes);
                              
                              // turn the hash to a string and return it
                              string sResult = BitConverter.ToString(encodedBytes).Replace("-", "");
                              // or: string sResult = Convert.ToBase64String(encodedBytes);
                              return sResult;
                              

                              }

                              now, in your login form, you ask to enter a username and a password, let's say you get back "jdoe" and "supersecret", at this point, you just call the above function this way

                              string hashValue = getKey(userName, userPass);

                              and the hashvalue will now contain something like "752dcc62c07fb4652981add596e1427b" now, with this value in your hands, you run a query on your database user table seeking for the user name (jdoe) and, if found, you compare the salted MD5 hash stored as the password with the one you just generated and, if they match, you grant access to the user. At this point, in case you need to use the password "in clear", you may just encrypt the password you received and store it into a session cookie, this will give you VOLATILE (temporary) storage and, while it will allow you to retrieve the password for the session lifetime, you won't in reality store the password anywhere on your server and... retrieving a password from a salted hash isn't exactly an easy task, believe me :) HTH

                              O Offline
                              O Offline
                              ObiWan_MCC
                              wrote on last edited by
                              #16

                              forgot; as for encrypting/decrypting, you may use the following code (not mine, but I'm sorry to say I don't remember where I found it)

                              // Encrypt the given string using AES. The string can be decrypted using
                              // DecryptString(). The sharedSecret parameters must match.
                              public string EncryptString(string plainText, string sharedSecret)
                              {
                              if (string.IsNullOrEmpty(plainText))
                              throw new ArgumentNullException("plainText");
                              if (string.IsNullOrEmpty(sharedSecret))
                              throw new ArgumentNullException("sharedSecret");

                              string outStr = null;                       // Encrypted string to return
                              RijndaelManaged aesAlg = null;              // RijndaelManaged object used to encrypt the data.
                              
                              try
                              {
                                  // generate the key from the shared secret and the salt
                                  Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(sharedSecret, this.\_salt);
                              
                                  // Create a RijndaelManaged object
                                  aesAlg = new RijndaelManaged();
                                  aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
                              
                                  // Create a decrytor to perform the stream transform.
                                  ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
                              
                                  // Create the streams used for encryption.
                                  using (MemoryStream msEncrypt = new MemoryStream())
                                  {
                                      // prepend the IV
                                      msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof(int));
                                      msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);
                                      using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                                      {
                                          using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                                          {
                                              //Write all data to the stream.
                                              swEncrypt.Write(plainText);
                                          }
                                      }
                                      outStr = Convert.ToBase64String(msEncrypt.ToArray());
                                  }
                              }
                              finally
                              {
                                  // Clear the RijndaelManaged object.
                                  if (aesAlg != null)
                                      aesAlg.Clear();
                              }
                              
                              // Return the encrypted bytes from the memory stream.
                              return outStr;
                              

                              }

                              // Decrypt the given string. Assumes the string was encrypted using
                              // EncryptString(), using an identical sharedSecret.
                              public string DecryptString(string cipherText, string sharedSecret)
                              {
                              if (string.IsNullOrEmpty(cipherText))
                              throw new ArgumentNullException("cipherText");
                              if (string.IsNullOrEmpty(sharedSecret))
                              throw new ArgumentNullException("shar

                              1 Reply Last reply
                              0
                              • O ObiWan_MCC

                                I think you're approaching the issue the wrong way, see, you DON'T need to know the password (nor to store it); all you need to do is checking that it is correct For such a task, all you'll need will be using an MD5 "salted" hash; just to be clear, let's say you have the following code

                                // generates the unique (salted) hash of a string
                                private static string getKey(string sSalt, string sKey)
                                {
                                Byte[] originalBytes, encodedBytes;
                                MD5 hash = new MD5CryptoServiceProvider();
                                // or: SHA256 hash = new SHA256CryptoServiceProvider();

                                // generate the hash value
                                originalBytes = ASCIIEncoding.Default.GetBytes(sSalt + "." + sKey);
                                encodedBytes = hash.ComputeHash(originalBytes);
                                
                                // turn the hash to a string and return it
                                string sResult = BitConverter.ToString(encodedBytes).Replace("-", "");
                                // or: string sResult = Convert.ToBase64String(encodedBytes);
                                return sResult;
                                

                                }

                                now, in your login form, you ask to enter a username and a password, let's say you get back "jdoe" and "supersecret", at this point, you just call the above function this way

                                string hashValue = getKey(userName, userPass);

                                and the hashvalue will now contain something like "752dcc62c07fb4652981add596e1427b" now, with this value in your hands, you run a query on your database user table seeking for the user name (jdoe) and, if found, you compare the salted MD5 hash stored as the password with the one you just generated and, if they match, you grant access to the user. At this point, in case you need to use the password "in clear", you may just encrypt the password you received and store it into a session cookie, this will give you VOLATILE (temporary) storage and, while it will allow you to retrieve the password for the session lifetime, you won't in reality store the password anywhere on your server and... retrieving a password from a salted hash isn't exactly an easy task, believe me :) HTH

                                S Offline
                                S Offline
                                Saul Johnson
                                wrote on last edited by
                                #17

                                Hello, Thank you for your answer. This is undoubtedly how I would go about authenticating passwords in any other circumstances but these, generating hashes using MD5 or (my personal preference) SHA-256. I am working with a web service from a Windows Forms application, and a password is required to work with this web service. Usually, I'd show a prompt and ask the user to input the password to authenticate when it starts, but the user requirements state that users must not need to enter any sort of authentication information in order to work with the application in the interest of ease-of-use. What I was looking for was a way to store this username and password locally in such a way that only my application would be able to access and use them. As it seems that this isn't really possible, I've put in place stricter controls and guidelines for where and when the software can be used and used misdirection and obfuscation as suggested by previous answers to make it more difficult for these credentials to be stolen. However, as you correctly say, the only way to really keep a password safe it to authenticate against its hash. SixOfTheClock

                                A programming language is to a programmer what a fine hat is to one who is fond of fancy garden parties. Just don't try wearing any .NET language on your head. Some of them are sharp.

                                O 1 Reply Last reply
                                0
                                • B BrainiacV

                                  Not sure if this will help, Back in the early days of microcomputers, some publishers tried to encrypt their programs to keep them from being pirated. After you entered a key, a subroutine would be called to decrypt the code. The sneaky bit was that right after the subroutine call, there was additional code, but, the program never reached it. Part of the decryption overlaid the system stack and so the subroutine return went someplace else, rather than the legitimate looking code that followed the decryption. So I guess in a long winded way, I am suggesting the use of misdirection in addition to the indirection that has been suggested above. And then repeat. It won't stop them, but it could really slow them down.

                                  Psychosis at 10 Film at 11 Those who do not remember the past, are doomed to repeat it. Those who do not remember the past, cannot build upon it.

                                  S Offline
                                  S Offline
                                  Saul Johnson
                                  wrote on last edited by
                                  #18

                                  Hello, That's a very clever suggestion that I certainly wouldn't have thought of, and I'll undoubtedly be looking into it. Thank you very much indeed. SixOfTheClock

                                  A programming language is to a programmer what a fine hat is to one who is fond of fancy garden parties. Just don't try wearing any .NET language on your head. Some of them are sharp.

                                  1 Reply Last reply
                                  0
                                  • J James H

                                    Whatever method you use I also like to have a set of "red herring" credentials - that looks likes a password, - e.g. config setting Password with some cyrptic looking string that could be an encrypted string - sends the b'rs of on a wild goose chase

                                    S Offline
                                    S Offline
                                    Saul Johnson
                                    wrote on last edited by
                                    #19

                                    Another way to make things that little bit more difficult to figure out for anyone with mischief on their mind. Excellent thank you. SixOfTheClock

                                    A programming language is to a programmer what a fine hat is to one who is fond of fancy garden parties. Just don't try wearing any .NET language on your head. Some of them are sharp.

                                    1 Reply Last reply
                                    0
                                    • S Saul Johnson

                                      Hello, Thank you for your answer. This is undoubtedly how I would go about authenticating passwords in any other circumstances but these, generating hashes using MD5 or (my personal preference) SHA-256. I am working with a web service from a Windows Forms application, and a password is required to work with this web service. Usually, I'd show a prompt and ask the user to input the password to authenticate when it starts, but the user requirements state that users must not need to enter any sort of authentication information in order to work with the application in the interest of ease-of-use. What I was looking for was a way to store this username and password locally in such a way that only my application would be able to access and use them. As it seems that this isn't really possible, I've put in place stricter controls and guidelines for where and when the software can be used and used misdirection and obfuscation as suggested by previous answers to make it more difficult for these credentials to be stolen. However, as you correctly say, the only way to really keep a password safe it to authenticate against its hash. SixOfTheClock

                                      A programming language is to a programmer what a fine hat is to one who is fond of fancy garden parties. Just don't try wearing any .NET language on your head. Some of them are sharp.

                                      O Offline
                                      O Offline
                                      ObiWan_MCC
                                      wrote on last edited by
                                      #20

                                      I see; given your situation there may be another possible solution; assuming that the webservice you're calling is hosted on a different box (or instance), and given that you don't have the code for the service, you may create your own webservice app, embed the user credentials into such an app and install it on the same (or another) box/instance where the regular webservice lives, this way, your webservice will act as a "proxy" so that your winforms app will call your webservice w/o any credentials and the latter will act as a "proxy" to the real webservice (and will pass it the needed credentials)

                                      1 Reply Last reply
                                      0
                                      Reply
                                      • Reply as topic
                                      Log in to reply
                                      • Oldest to Newest
                                      • Newest to Oldest
                                      • Most Votes


                                      • Login

                                      • Don't have an account? Register

                                      • Login or register to search.
                                      • First post
                                        Last post
                                      0
                                      • Categories
                                      • Recent
                                      • Tags
                                      • Popular
                                      • World
                                      • Users
                                      • Groups