Fully cross-platform (desktop, web, console and mobile) encryption

Cross-platform encryption now includes iOS!

FYI I have finished writing (and have successfully tested) two new methods that allow the encryption and decryption of any MemoryBlock between MBS Encryption Kit and MBS Plugin. This means you can even place encrypted data (eg credit card info, secret questions/answers, etc) into a database that is accessible from desktop, web and now iOS (and hopefully eventually Android).

For large database queries I usually Zip compress before I encrypt, so it works for binary data too. Encryption returns a Base64, so it can be stored in any database or file. I tested it with a 1 GB string on iOS, macOS and Windows and it all went well, but crashed when I tried a 10 GB string!
It uses:

  1. A MemoryBlock as encryption input and decryption output (rather than Text) so that zipped and binary data can be encrypted too
  2. Allows an IV Key for extra security
  3. Allows a variable Salt length (using CommonCryptoMB.generateBytes1(SaltSize) and RandomBytesStringMBS(SaltSize)) for extra security
  4. Returns the encryption result as Base64 so it can be placed in databases and files easily (and is smaller than Hex)
  5. Adds a CheckHash to verify on decryption if the text has been tampered with
  6. Cross tested the Base64 output from iOS into MBS Plugin and vice versa, to ensure the two methods are compatible
  7. Tested with plain text and ZipMB.Compress() zipped binary text on iOS
  8. Tested with macOS and Windows 10. Some testing with Linux too.

To encrypt:

Text = Encrypt(DecryptedData As Xojo.Core.MemoryBlock, KeyText As Text, IVKey As Text, SaltSize As Integer = 8)

To Decrypt:

Xojo.Core.MemoryBlock = Decrypt(InputText As Text, KeyText As Text, IVKey As Text, SaltSize As Integer = 8)

1 Like

Sounds great @DavidCox and welcome to the forum!

Is there a link to test the code?

I have included the new Encrypt and Decrypt methods and how they can be called below. You will need access to the MBS Encryption plugin and the very latest MBS Encryption Kit for it to work.

Here is how you might use it on iOS (the field names should be apparent):

Dim IVKey As Text = "1234567890ABCDE"
Dim SaltSize As Integer = 8

//plain Text works!
Dim EncryptedBase64 As Text = Encrypt(Xojo.Core.TextEncoding.UTF8.ConvertTextToData(InputText.Text), KeyText.Text, IVKey, SaltSize)
EncryptedKitText.Text = EncryptedBase64

Dim DecryptedMB As Xojo.Core.MemoryBlock = Decrypt(EncryptedBase64, KeyText.Text, IVKey, SaltSize)
DecryptedKitText.Text = Xojo.Core.TextEncoding.UTF8.ConvertDataToText(DecryptedMB)

// zipped data also works!
Dim ZippedTextMB As Xojo.Core.MemoryBlock = ZipMB.Compress(Xojo.Core.TextEncoding.UTF8.ConvertTextToData(InputText.Text))
Dim ZipEncryptedBase64 As Text = Encrypt(ZippedTextMB, KeyText.Text, IVKey, SaltSize)
EncryptedKitText.Text = ZipEncryptedBase64

Dim ZipDecryptedMB As Xojo.Core.MemoryBlock = Decrypt(ZipEncryptedBase64, KeyText.Text, IVKey, SaltSize)
Dim UnZippedTextMB As Xojo.Core.MemoryBlock = ZipMB.Decompress(ZipDecryptedMB)
Dim UnZippedText As Text = Xojo.Core.TextEncoding.UTF8.ConvertDataToText(UnZippedTextMB)
If UnZippedText <> InputText.Text Then
  Break
End If
DecryptedKitText.Text = UnZippedText

Here is how you might use it on desktop, web and console:

Dim InputString As Text = "Encrypt me `⁄€‹›fifl‡°·‚—± ≠–ºª•¶§∞¢£™¡`≤≥÷…æ“‘«–≠¯˘¿ÚÆ”’»±—"
Dim KeyText As String = "Test"
Dim IVKey As Text = "1234567890ABCDE"
Dim SaltSize As Integer = 8
Dim InputCoreMB As New Xojo.Core.MemoryBlock(CommonCryptoMB.generateBytes1(102400000))
Dim EncryptedBase64 As Text
Dim DecryptedMB As Xojo.Core.MemoryBlock

//plain Text works!
EncryptedBase64 = Encrypt(Xojo.Core.TextEncoding.UTF8.ConvertTextToData(InputString, True), KeyText.ToText, IVKey, SaltSize)
EncryptedBase64 = Encrypt(InputCoreMB, KeyText.ToText, IVKey, SaltSize)

DecryptedMB = Decrypt(EncryptedBase64, KeyText.ToText, IVKey, SaltSize)
DecryptedKitText = Xojo.Core.TextEncoding.UTF8.ConvertDataToText(DecryptedMB) 'only do this when decrypting text!
'If DecryptedKitText <> InputString Then
If InputCoreMB <> DecryptedMB Then
  MsgBox "Failed to decrypt"
End If

Here is the encryption method:

Protected Function Encrypt(DecryptedData As Xojo.Core.MemoryBlock, KeyText As Text, IVKey As Text, SaltSize As Integer = 8) as Text
  #If TargetiOS Then 'iOS and macOS only
    // create the salt and generate a 64 character CheckHash
    Dim Salt As Xojo.Core.MemoryBlock = CommonCryptoMB.generateBytes1(SaltSize)
    Dim CheckHash As Xojo.Core.MemoryBlock = CommonCryptoMB.Hash(CommonCryptoMB.Hashes.SHA512, DecryptedData)
        
    // get hash of key
    Dim KeyHash As Xojo.Core.MemoryBlock = HashKey(KeyText)
        
    // set to encrypt
    Dim Operation As CommonCryptoMB.CryptoOperation = CommonCryptoMB.CryptoOperation.Encrypt
        
    // AES
    Dim Algorithm As CommonCryptoMB.CryptoAlgorithm = CommonCryptoMB.CryptoAlgorithm.AES
        
    // CBC mode and padding
    Dim Options As Integer = BitWiseOR(CommonCryptoMB.kCCOptionPKCS7Padding, CommonCryptoMB.kCCOptionCBCMode)
        
     // IV Key
    Dim IV As Xojo.Core.MemoryBlock
    If IVKey <> "" Then 'leave as nil?
      IV = Xojo.Core.TextEncoding.UTF8.ConvertTextToData(IVKey)
    End If
        
    // get data to encrypt as memoryblock
    Dim EncryptedData As Xojo.Core.MemoryBlock = CommonCryptoMB.Crypt(Operation, Algorithm, Options, KeyHash, DecryptedData, IV)
        
    // append salt and check Hash
    Dim tempMutableMemoryBlock As New Xojo.Core.MutableMemoryBlock(Salt)
    tempMutableMemoryBlock.Append(EncryptedData)
    tempMutableMemoryBlock.Append(CheckHash)
        
    Return CommonCryptoMB.EncodeBase64Memory(New Xojo.Core.MemoryBlock(tempMutableMemoryBlock))
        
  #Else 'macOS, Windows, Linux, desktop, web, console only, but not iOS
    // via MBS Encryption Plugin for Mac/Windows/Linux
    Dim Salt As String = RandomBytesStringMBS(SaltSize)
    Var tempMemoryBlock As MemoryBlock = DecryptedData.Data 'convert from Xojo.Core.MemoryBlock to MemoryBlock to String
    Dim InputData As String = tempMemoryBlock.StringValue(0, DecryptedData.Size) 'cannot use TextEncoding.UTF8 as it might be binary data
    tempMemoryBlock = nil 'clear the RAM
    Dim CheckHash As String = SHA512MBS.Hash(InputData)
        
    // get key
    Dim KeyHash As String = SHA256MBS.Hash(KeyText)
        
    // encrypt
    Dim ecipher As CipherMBS = CipherMBS.aes_256_cbc
        
    // IV Key
    Dim IV As MemoryBlock
    If IVKey <> "" Then 'leave as nil?
      IV = IVKey
    End If
        
    If ecipher.EncryptInit(KeyHash, IV) Then
      ecipher.Padding = True
      Dim EncryptedData As String = ecipher.ProcessString(InputData) + ecipher.FinalizeAsString
          
      Return EncodeBase64MBS(Salt + EncryptedData + CheckHash, 0, "").ToText
          
    Else
      Return ""
    End If
  #EndIf 
End Function

Here is the decryption method:

Protected Function Decrypt(InputText As Text, KeyText As Text, IVKey As Text, SaltSize As Integer = 8) as Xojo.Core.MemoryBlock
  #If TargetiOS Then 'iOS and macOS only
    // don't need to create Salt
    
    // get hash of key
    Dim KeyHash As Xojo.Core.MemoryBlock = HashKey(KeyText)
    
    // set to decrypt
    Dim Operation As CommonCryptoMB.CryptoOperation = CommonCryptoMB.CryptoOperation.Decrypt
    
    // AES
    Dim Algorithm As CommonCryptoMB.CryptoAlgorithm = CommonCryptoMB.CryptoAlgorithm.AES
    
    // CBC mode and padding
    Dim Options As Integer = BitWiseOR(CommonCryptoMB.kCCOptionPKCS7Padding, CommonCryptoMB.kCCOptionCBCMode)
    
    // IV Key
    Dim IV As Xojo.Core.MemoryBlock
    If IVKey <> "" Then 'leave as nil?
      IV = Xojo.Core.TextEncoding.UTF8.ConvertTextToData(IVKey)
    End If
    
    // get data to decrypt as memoryblock
    Dim EncryptedData As Xojo.Core.MemoryBlock = CommonCryptoMB.DecodeBase64Memory(InputText)
    
    // remove salt and check Hash
    Dim CheckHash As Xojo.Core.MemoryBlock = EncryptedData.Right(64)
    EncryptedData = EncryptedData.Mid(SaltSize, EncryptedData.Size - 64 - SaltSize) 'remove Salt and CheckHash, zero-based so start from character #8
    
    Dim DecryptedData As Xojo.Core.MemoryBlock = CommonCryptoMB.Crypt(Operation, Algorithm, Options, KeyHash, EncryptedData, IV)
    
    If CheckHash <> CommonCryptoMB.Hash(CommonCryptoMB.Hashes.SHA512, DecryptedData) Then 'check that the Hash is still correct ie the text has not been tampered with
      Return Nil
    End If
    
    Return DecryptedData
    
  #Else 'macOS, Windows, Linux, desktop, web, console only, but not iOS
    // don't need to create Salt
    
    // get hash of key
    Dim KeyHash As String = SHA256MBS.Hash(KeyText)
    
    // get data to decrypt as String
    Dim EncryptedData As String = DecodeBase64MBS(InputText)
    
    // remove salt and check Hash
    Dim CheckHash As String = EncryptedData.RightB(64)
    EncryptedData = EncryptedData.MiddleBytes(SaltSize, EncryptedData.LenB - 64 - SaltSize) 'remove Salt and CheckHash, zero-based so start from character #8
    
    // IV Key
    Dim IV As MemoryBlock
    If IVKey <> "" Then 'leave as nil?
      IV = IVKey
    End If
    
    // now decrypt
    Dim dcipher As CipherMBS = CipherMBS.aes_256_CBC
    If dcipher.DecryptInit(KeyHash, IV) Then
      dcipher.Padding = True
      
      Dim DecryptedData As String = DefineEncoding(dcipher.ProcessString(EncryptedData) + dcipher.FinalizeAsString, Encodings.UTF8)
      
      If CheckHash <> SHA512MBS.Hash(DecryptedData) Then 'check that the Hash is still correct ie the text has not been tampered with
        Return Nil
      End If
      
      'Dim ReturnData As Xojo.Core.MemoryBlock = Xojo.Core.TextEncoding.UTF8.ConvertTextToData(DecryptedData.ToText)
      Dim tempMemoryBlock As MemoryBlock = DecryptedData
      Dim ReturnData As New Xojo.Core.MemoryBlock(tempMemoryBlock, tempMemoryBlock.Size)
      tempMemoryBlock = nil 'clear the memory
      
      Return ReturnData
      
    End If
  #EndIf    
End Function