Encryption/Decryption in Xamarin

jasonmadrigaljasonmadrigal USMember

Hi,
I'm working with local database, and I want to encrypt the strings when save to tables, when I want to show info from database to the user I want to decrypt the info.
I'm using an example that I found for .NET here http://www.codeproject.com/Articles/33350/Encrypting-Query-Strings
I'm not using it to encrypt querystrings but it works for everything.
the Encryption method works well, but the Decryption method always throws an System.Security.Cryptography.CryptographicException: Bad PKCS7 padding. Invalid length...
Searching on the web(google) I realized that is a general problem of Mono, but I cant find a solution that could make this example to work or any public solution.

It is possible to make the example to work in xamarin ?

Posts

  • KMullinsKMullins USMember, Xamarin Team Xamurai

    @jasonmadrigal‌,

    Try using this little routine:

    using System;
    using System.Security.Cryptography;
    using System.Text;
    using System.IO;
    
    namespace System.Security.Cryptography
    {
        /// <summary>
        /// The <see cref="System.Security.Cryptography.Crypto"/> provides an easy way encrypt and decrypt
        /// data using a simple password.
        /// </summary>
        /// <remarks>
        /// Code based on the book "C# 3.0 in a nutshell by Joseph Albahari" (pages 630-632)
        /// and from this StackOverflow post by somebody called Brett
        /// http://stackoverflow.com/questions/202011/encrypt-decrypt-string-in-net/2791259#2791259
        /// </remarks>
        static internal class Crypto
        {
            // Define the secret salt value for encrypting data
            private static readonly byte[] salt = Encoding.ASCII.GetBytes("Xamarin.iOS Version: 7.0.6.168");
    
            /// <summary>
            /// Takes the given text string and encrypts it using the given password.
            /// </summary>
            /// <param name="textToEncrypt">Text to encrypt.</param>
            /// <param name="encryptionPassword">Encryption password.</param>
            internal static string Encrypt(string textToEncrypt, string encryptionPassword)
            {
                var algorithm = GetAlgorithm(encryptionPassword);
    
                //Anything to process?
                if (textToEncrypt==null || textToEncrypt=="") return "";
    
                byte[] encryptedBytes;
                using (ICryptoTransform encryptor = algorithm.CreateEncryptor(algorithm.Key, algorithm.IV))
                {
                    byte[] bytesToEncrypt = Encoding.UTF8.GetBytes(textToEncrypt);
                    encryptedBytes = InMemoryCrypt(bytesToEncrypt, encryptor);
                }
                return Convert.ToBase64String(encryptedBytes);
            }
    
            /// <summary>
            /// Takes the given encrypted text string and decrypts it using the given password
            /// </summary>
            /// <param name="encryptedText">Encrypted text.</param>
            /// <param name="encryptionPassword">Encryption password.</param>
            internal static string Decrypt(string encryptedText, string encryptionPassword)
            {
                var algorithm = GetAlgorithm(encryptionPassword);
    
                //Anything to process?
                if (encryptedText==null || encryptedText=="") return "";
    
                byte[] descryptedBytes;
                using (ICryptoTransform decryptor = algorithm.CreateDecryptor(algorithm.Key, algorithm.IV))
                {
                    byte[] encryptedBytes = Convert.FromBase64String(encryptedText);
                    descryptedBytes = InMemoryCrypt(encryptedBytes, decryptor);
                }
                return Encoding.UTF8.GetString(descryptedBytes);
            }
    
            /// <summary>
            /// Performs an in-memory encrypt/decrypt transformation on a byte array.
            /// </summary>
            /// <returns>The memory crypt.</returns>
            /// <param name="data">Data.</param>
            /// <param name="transform">Transform.</param>
            private static byte[] InMemoryCrypt(byte[] data, ICryptoTransform transform)
            {
                MemoryStream memory = new MemoryStream();
                using (Stream stream = new CryptoStream(memory, transform, CryptoStreamMode.Write))
                {
                    stream.Write(data, 0, data.Length);
                }
                return memory.ToArray();
            }
    
            /// <summary>
            /// Defines a RijndaelManaged algorithm and sets its key and Initialization Vector (IV) 
            /// values based on the encryptionPassword received.
            /// </summary>
            /// <returns>The algorithm.</returns>
            /// <param name="encryptionPassword">Encryption password.</param>
            private static RijndaelManaged GetAlgorithm(string encryptionPassword)
            {
                // Create an encryption key from the encryptionPassword and salt.
                var key = new Rfc2898DeriveBytes(encryptionPassword, salt);
    
                // Declare that we are going to use the Rijndael algorithm with the key that we've just got.
                var algorithm = new RijndaelManaged();
                int bytesForKey = algorithm.KeySize / 8;
                int bytesForIV = algorithm.BlockSize / 8;
                algorithm.Key = key.GetBytes(bytesForKey);
                algorithm.IV = key.GetBytes(bytesForIV);
                return algorithm;
            }
    
        }
    
    }
    

    It always seems to do the trick for me.

    Please let me know if you have any questions.

    Thanks,

    Kevin

  • jasonmadrigaljasonmadrigal USMember

    Hi Kevin your solution works.
    Thanks.

  • RicardoColladaRicardoCollada USMember ✭✭

    There is a way to do that in a PCL? I cant find the System.Security.Cryptography namespace in PCLs references.

  • CheesebaronCheesebaron DKInsider, University mod

    You will have to use a library to enable you using Crypto in a PCL. This could be: https://www.nuget.org/packages/PCLCrypto/

  • ephraimdovephraimdov AEMember

    Try this one....String Encryption and Decryption example

    Dov

  • JoeProJoePro CAUniversity ✭✭✭

    If you're using SQLite for local data storage, you have another options: SqlCipher. Yeah, I know the Component isn't free if you don't have an Enterprise license, but you can download the iOS source code and compile it yourself for free. That's what I do and it works really well. No need to encrypt/decrypt anything since everything is already transparently encrypted for you.

  • Chip.7195Chip.7195 USMember

    @Cheesebaron https://www.nuget.org/packages/PCLCrypto/ is almost 100% completely INADEQUATE. (Inappropriate / unacceptable from a cryptographic standpoint.)

  • Chip.7195Chip.7195 USMember

    @KMullins How about a less-than-"little"-routine. How about a standard set of cryptographic utilities for PCL hosted by Xamarin and/or MicroSoft? -- I was just looking at Microsoft's offerings on GitHub the other day and noticed "Xamarin" as a recent contributor to a number of their (147+ repos).

    Given Implicit, Explict and Operator... why can't we expose basic C-type methods to a "safe" (not "unsafe") perspective?

    Why do we have to choose between PCL and BCL?

    Don't all mobile platforms somehow support C++ natively? Why can't we just simply expose this, alone? (And have wrapper methods, the same as all post-modern languages. -- Who does something doing C/C++ does have to be labeled as unsafe, or otherwise unavailable to usage... exceptions will still be thrown, and security will still be breached.)

  • JanZemanJanZeman USUniversity

    Hi @Chip.7195, can you be more concrete? When you say such a strong A (inadequate, inappropriate, unacceptable) you should also say B and provide at least SOME explanation behind that statement.

  • tfierenstfierens IEMember

    Hi @KMullins , I've tried to add the code you provided to the "Portable" part of my Xamarin.Forms solution, but it's not recognising any of the encryption code i.e. ICryptoTransform, CryptoStream, RijndaelManaged, etc... I assume it's because I need to add a reference but I can't seem to see it anywhere? Is there a PCL I should download from Nuget or isn't supported in a portable project? Thanks.

  • AndrewArnottAndrewArnott USMember ✭✭

    @Chip.7195 I'm curious why you feel PCLCrypto is so inadequate. Is it missing functionality or its design that you disagree with?

  • OnurHazarOnurHazar USUniversity ✭✭✭

    Hello @KMullins @Cheesebaron , I've added PCLCrypto package but it seems RijndaelManaged could not be found. System.Security.Cryptography is also missing in my PCL so I can not use that. Any solutions?

  • AlecTucker.2208AlecTucker.2208 AUInsider, University, Developer Group Leader mod

    Onur,

    Yes - it's not available in the PCL. You'll have to branch out to the platform projects to access this.

  • AlexReyesAlexReyes USUniversity ✭✭

    @onur.hazar i can share a sqlite extension with you that do field base encryption

  • alexrainmanalexrainman USMember ✭✭

    @onur.hazar i am not the original author of this plugin but, i made some fixes from the original one like avoiding to object in memory to be encrypted and using generated Salts instead of hardcoded ones:

    https://drive.google.com/file/d/0B6hZDQudMRBUY2NCaHlPdzNTVVU/view?usp=sharing

  • OnurHazarOnurHazar USUniversity ✭✭✭

    Thanks! I'll give a try

  • Hi,

    I download this sample code and work fine!!

    http://www.c-sharpcorner.com/uploadfile/4088a7/using-cryptography-in-portable-xamarin-formswindows-phone/

    This code by Raj Bandi .

  • Thx!!

  • CluberlangCluberlang USMember
    edited June 2016

    public static byte[] HASHString(string txt)
    {
    byte[] bytPwd =Encoding.UTF8.GetBytes(txt);
    SHA512Managed SHA5 = new SHA512Managed();
    byte[] hash = SHA5.ComputeHash(bytPwd);
    {
    return hash;
    }
    }

  • PoojaShettyPoojaShetty USMember

    Hi,
    I have tried with the above snippet from @jasonmadrigal‌ in PCL,but neither the RijndaelManaged algorithm is getting referred by PCL Project (PCLcrypto) for Any Profile Nor System.Security.Cryptography can be used. But can only be referred by Droid and IOS.
    Is there any reference or sample code for PCLcrypto or any other Encryption framework to work in Portable Class Library that can be consumed in Android and IOS either.

    Thanks.

  • RexHopeRexHope PHMember ✭✭

    @PoojaShetty said:
    Hi,
    I have tried with the above snippet from @jasonmadrigal‌ in PCL,but neither the RijndaelManaged algorithm is getting referred by PCL Project (PCLcrypto) for Any Profile Nor System.Security.Cryptography can be used. But can only be referred by Droid and IOS.
    Is there any reference or sample code for PCLcrypto or any other Encryption framework to work in Portable Class Library that can be consumed in Android and IOS either.

    Thanks.

    There is no RijndaelManaged algorithm for PCLCrypto, you need to use the System.Security.Cryptography package. In order to do that, you need a .net standard library, targeting min .net standard 1.4, alternatively, if you ever do not want it since it doesn't support <=4.5 .NET framework you need to use a dependency service in order to write platform specific codes.

  • AlecTucker.2208AlecTucker.2208 AUInsider, University, Developer Group Leader mod

    Hey @PoojaShetty - you can put your crypto code into a shared project that's referenced by both the iOS and Android projects. This is a classic case where I would have both a PCL and a Shared Project. The shared project would contain a service class to handle the encryption / decryption, and everything else would go into my PCL.

  • prishahprishah CAMember ✭✭
    edited March 2018

    @KMullins your code working perfectly in my Xamarin.Android, just have one question one of code line below:

    Code Line : private static readonly byte[] salt= Encoding.ASCII.GetBytes("Xamarin.iOS Version: 7.0.6.168");
    why do we only need Xamarin.iOS version but not Xamarin.Android version?

    I have created shared class "PasswordEncryptCrypt" that is going to use by both iOS and Android, but my question is that above line of code is only for Xamarin.iOS but not Xamarin.Android right?

    I have used in my class : private static readonly byte[] salt = Encoding.ASCII.GetBytes("Xamarin.Android Version: 8.0.2.1");
    and this works fine on Android

    and if I use : private static readonly byte[] salt = Encoding.ASCII.GetBytes("Xamarin.iOS Version: 11.3.0.47");
    this will also work in my Android device. I haven't check on iOS device yet

    Please correct me if I understood wrong that line above.

    @KMullins said:
    @jasonmadrigal‌,

    Try using this little routine:

    using System;
    using System.Security.Cryptography;
    using System.Text;
    using System.IO;

    namespace System.Security.Cryptography
    {
    ///


    /// The provides an easy way encrypt and decrypt
    /// data using a simple password.
    ///

    ///
    /// Code based on the book "C# 3.0 in a nutshell by Joseph Albahari" (pages 630-632)
    /// and from this StackOverflow post by somebody called Brett
    /// http://stackoverflow.com/questions/202011/encrypt-decrypt-string-in-net/2791259#2791259
    ///
    static internal class Crypto
    {
    // Define the secret salt value for encrypting data
    private static readonly byte[] salt = Encoding.ASCII.GetBytes("Xamarin.iOS Version: 7.0.6.168");

          /// <summary>
          /// Takes the given text string and encrypts it using the given password.
          /// </summary>
          /// <param name="textToEncrypt">Text to encrypt.</param>
          /// <param name="encryptionPassword">Encryption password.</param>
          internal static string Encrypt(string textToEncrypt, string encryptionPassword)
          {
              var algorithm = GetAlgorithm(encryptionPassword);
    
              //Anything to process?
              if (textToEncrypt==null || textToEncrypt=="") return "";
              
              byte[] encryptedBytes;
              using (ICryptoTransform encryptor = algorithm.CreateEncryptor(algorithm.Key, algorithm.IV))
              {
                  byte[] bytesToEncrypt = Encoding.UTF8.GetBytes(textToEncrypt);
                  encryptedBytes = InMemoryCrypt(bytesToEncrypt, encryptor);
              }
              return Convert.ToBase64String(encryptedBytes);
          }
    
          /// <summary>
          /// Takes the given encrypted text string and decrypts it using the given password
          /// </summary>
          /// <param name="encryptedText">Encrypted text.</param>
          /// <param name="encryptionPassword">Encryption password.</param>
          internal static string Decrypt(string encryptedText, string encryptionPassword)
          {
              var algorithm = GetAlgorithm(encryptionPassword);
    
              //Anything to process?
              if (encryptedText==null || encryptedText=="") return "";
              
              byte[] descryptedBytes;
              using (ICryptoTransform decryptor = algorithm.CreateDecryptor(algorithm.Key, algorithm.IV))
              {
                  byte[] encryptedBytes = Convert.FromBase64String(encryptedText);
                  descryptedBytes = InMemoryCrypt(encryptedBytes, decryptor);
              }
              return Encoding.UTF8.GetString(descryptedBytes);
          }
          
          /// <summary>
          /// Performs an in-memory encrypt/decrypt transformation on a byte array.
          /// </summary>
          /// <returns>The memory crypt.</returns>
          /// <param name="data">Data.</param>
          /// <param name="transform">Transform.</param>
          private static byte[] InMemoryCrypt(byte[] data, ICryptoTransform transform)
          {
              MemoryStream memory = new MemoryStream();
              using (Stream stream = new CryptoStream(memory, transform, CryptoStreamMode.Write))
              {
                  stream.Write(data, 0, data.Length);
              }
              return memory.ToArray();
          }
          
          /// <summary>
          /// Defines a RijndaelManaged algorithm and sets its key and Initialization Vector (IV) 
          /// values based on the encryptionPassword received.
          /// </summary>
          /// <returns>The algorithm.</returns>
          /// <param name="encryptionPassword">Encryption password.</param>
          private static RijndaelManaged GetAlgorithm(string encryptionPassword)
          {
              // Create an encryption key from the encryptionPassword and salt.
              var key = new Rfc2898DeriveBytes(encryptionPassword, salt);
              
              // Declare that we are going to use the Rijndael algorithm with the key that we've just got.
              var algorithm = new RijndaelManaged();
              int bytesForKey = algorithm.KeySize / 8;
              int bytesForIV = algorithm.BlockSize / 8;
              algorithm.Key = key.GetBytes(bytesForKey);
              algorithm.IV = key.GetBytes(bytesForIV);
              return algorithm;
          }
          
      }
    

    }

    It always seems to do the trick for me.

    Please let me know if you have any questions.

    Thanks,

    Kevin

  • It is not working in PCL. if you are using SQL light in your local database. it stores data in Xamarin. Android data file.

  • Achraf_benalayaAchraf_benalaya USMember ✭✭

    This worked for me :

    https://tekeye.uk/visual_studio/encrypt-decrypt-c-sharp-string

    //Don't forget the using System.Security.Cryptography; statement when you add this class
    public static class Encrypt
    {
        // This size of the IV (in bytes) must = (keysize / 8).  Default keysize is 256, so the IV must be
        // 32 bytes long.  Using a 16 character string here gives us 32 bytes when converted to a byte array.
        private const string initVector = "pemgail9uzpgzl88";
        // This constant is used to determine the keysize of the encryption algorithm
        private const int keysize = 256;
        //Encrypt
        public static string EncryptString(string plainText, string passPhrase)
        {
            byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
            PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
            byte[] keyBytes = password.GetBytes(keysize / 8);
            RijndaelManaged symmetricKey = new RijndaelManaged();
            symmetricKey.Mode = CipherMode.CBC;
            ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
            MemoryStream memoryStream = new MemoryStream();
            CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
            cryptoStream.FlushFinalBlock();
            byte[] cipherTextBytes = memoryStream.ToArray();
            memoryStream.Close();
            cryptoStream.Close();
            return Convert.ToBase64String(cipherTextBytes);
        }
        //Decrypt
        public static string DecryptString(string cipherText, string passPhrase)
        {
            byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
            byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
            PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
            byte[] keyBytes = password.GetBytes(keysize / 8);
            RijndaelManaged symmetricKey = new RijndaelManaged();
            symmetricKey.Mode = CipherMode.CBC;
            ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
            MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
            CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
            byte[] plainTextBytes = new byte[cipherTextBytes.Length];
            int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
            memoryStream.Close();
            cryptoStream.Close();
            return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
        }
    }
    
Sign In or Register to comment.