B4J Question [B4X] XOR string encoding/decoding

Discussion in 'B4J Questions' started by luc-dev, Apr 16, 2019.

  1. luc-dev

    luc-dev Member Licensed User

    Hi,

    I am trying to write XOR encoding/decoding for B4X (I need to use it as a light weight and fast encoding/decoding cross plateforme solution with B4I, B4A, B4J and Lazarus/FPC). I know XOR is not the best/strongest encryption solution but it should be ok for my needs).

    The following code works but need Base64 encoding first (I was not able to directly encode a string with XOR when the initial string has non-ascii chars ie UTF-8).

    It would be great if someone knows a way to avoid the base64 encoding and help to increase the speed of this code :)

    Code:
    Sub Button1_Click
        
    Dim str As StringUtils
        
    Dim aStr1 As String
        
    Dim aStr2 As String
        
    Dim b As ByteConverter
        
    Dim By() As Byte
        
    Dim DT As Long = DateTime.Now
           
        
    For i = 0 To 1000000
            aStr1 = str.EncodeBase64(
    "ABCéè§ê:/%$€".GetBytes("UTF-8"))
            aStr1 = XorEncode(
    "MyKey", aStr1)
            aStr2 = XorDecode(
    "MyKey", aStr1)
            By = str.DecodeBase64(aStr2)
            aStr2 = B.StringFromBytes(By, 
    "UTF-8")
        
    Next
       
        
    Log("Ellapsed Time: " & (DateTime.Now - DT))
    End Sub

    Sub XorEncode(Key As String, Source As StringAs String
         
    Dim b As ByteConverter
         
    Dim IntVal As Int
         
    Dim IntVal As Int
         
    Dim aStrVal As String
         
    Dim aResult As StringBuilder
         aResult.Initialize
         
    Dim S1() As Byte = b.StringToBytes(Source, "UTF-8")
         
    Dim k1() As Byte = b.StringToBytes(Key, "UTF-8")

         
    For i = 0 To S1.Length-1
             IntVal = 
    Bit.Xor(k1(i Mod k1.Length), S1(i))
             aStrVal = 
    Bit.ToHexString(IntVal)
             
    If aStrVal.Length = 1 Then aStrVal = "0" & aStrVal
             aResult.Append(aStrVal)
         
    Next
         
    Return aResult.ToString
    End Sub

    Sub XorDecode(Key As String, Source As StringAs String
          
    Dim b As ByteConverter
          
    Dim aResult As String = ""
          
    Dim S1() As Byte = b.HexToBytes(Source)
          
    Dim k1() As Byte = b.StringToBytes(Key, "UTF-8")
          
    Dim ByteVals(S1.Length) As Byte
         
          
    For i = 0 To S1.Length -1
              ByteVals(i) = 
    Bit.Xor(k1(i Mod k1.Length), S1(i))
          
    Next
          aResult = 
    BytesToString(ByteVals, 0, ByteVals.Length, "UTF-8")
          
    Return aResult
    End Sub
    Thanks!
     
  2. MarkusR

    MarkusR Well-Known Member Licensed User

    if you encode a string=bytes with xor and other bytes (as key) the result is a byte array.
     
  3. luc-dev

    luc-dev Member Licensed User

    Thanks Markus,

    In fact, XorDecode works even without Base64 but XorEncode only works when the Source String doesn't contain non-ascii chars. When Source String has non-ascii chars (UTF-8), EncodeBase64 is the only solution found so far...
     
  4. MarkusR

    MarkusR Well-Known Member Licensed User

    i meant if you modify a string with xor its not a valid utf8 string output.
    it looks like this
    string->bytes->xor->bytes
    bytes->xor->bytes->string
     
  5. luc-dev

    luc-dev Member Licensed User

    The main problem here (I think) is in the string->bytes conversion in XorEncode. The string is converted to Byte() with
    Dim S1() As Byte = b.StringToBytes(Source, "UTF-8")
    but the resulting Byte array contains negative values.
    Here is the log output of S1(0) to S1(10) when calling XorEncode("MyKey", "ABCéè§ê:/%$€") (without EncodeBase64)

    S1(0) = 65 (A)
    S1(1) = 66 (B)
    S1(2) = 67 (C)
    S1(3) = -61
    S1(4) = -87
    S1(5) = -61
    S1(6) = -88
    S1(7) = -62
    S1(8) = -89
    S1(9) = -61
    S1(10) = -86

    "ABC" is correct but "éè§ê:/%$€" are not. Did you try the code?
     
  6. MarkusR

    MarkusR Well-Known Member Licensed User

    this xor all with 88 as example, this 88 can be replaced with a key value in the iteration
    Code:
    Sub Button1_Click
      
        
    Dim Bytes() As Byte
        Bytes = XorEncode(
    "ABCéè§ê:/%$€")
        
    Log(XorDecode(Bytes))
     
    End Sub

    Sub XorEncode(Source As StringAs Byte()

        
    Dim Bytes() As Byte
        Bytes = Source.GetBytes(
    "UTF8")

        
    Dim i As Int
        
    For i = 0 To Bytes.Length-1
            Bytes(i) = 
    Bit.Xor(Bytes(i),88)
        
    Next

        
    Return Bytes

    End Sub

    Sub XorDecode(Bytes() As Byte) As String
      
        
    Dim i As Int   
        
    For i = 0 To Bytes.Length -1
            Bytes(i) = 
    Bit.Xor(Bytes(i),88)
        
    Next

        
    Return BytesToString(Bytes, 0, Bytes.Length, "UTF-8")

    End Sub
    Plan B if you need to store the encryped bytes as base 64 string
    used lib b4xencryption
    Password (=Key) is a global variable used inside this subs
    and its insecure same xor
    Code:
    Sub EncryptText(text As StringAs String

        
    Dim c As B4XCipher

        
    Dim e() As Byte
        e = c.Encrypt(text.GetBytes(
    "utf8"), Password)
           
        
    Dim su As StringUtils
           
        
    Return su.EncodeBase64(e)

    End Sub

    Sub DecryptText(textb64 As StringAs String

        
    Try
            
    Dim c As B4XCipher
            
    Dim su As StringUtils
            
    Dim a() As Byte = su.DecodeBase64(textb64)
            
    If a.Length=0 Then Return ""
            
    Dim b() As Byte = c.Decrypt( a, Password)
               
            
    Return BytesToString(b, 0, b.Length, "UTF-8")
        
    Catch
                
    Log(LastException)
                
    Return ""
        
    End Try

    End Sub
     
    Last edited: Apr 16, 2019
  7. luc-dev

    luc-dev Member Licensed User

    Thank you Markus for spending your time trying to solve this.
    I did further testing but I didn't get the expected results :(

    Your XorEncode is fine but I need to store the result in a sqlite database, so I need to get a string from XorEncode, not Byte().

    Plan B could be fine too but unfortunately I need to be able to read and write the encrypted data from Lazarus/FPC (I can't use B4XCipher)

    Here is the code used in FPC, in case someone has a way to solve the XorEncode but I don't think this can be done with B4J (No offense here, it is just two different ways to work with strings):

    Code:
    function XorEncode(const Key, Source: string): string;

    var
      i: Integer;
      C: Byte;

    begin
      Result:=
    '';
      for i:=1 to Length(Source) do
        begin
        
    if Length(Key) > 0 then
          C:=Byte(Key[
    1 + ((i - 1mod Length(Key))]) xor Byte(Source[i])
        
    else
          C:=Byte(Source[i]);
        Result:=Result+AnsiLowerCase(intToHex(C, 
    2));
        
    end;
    end;
     
  8. MarkusR

    MarkusR Well-Known Member Licensed User

    and this?

    string->bytes->xor->bytes->hex string
    hex string->bytes->xor->bytes->string

    your FPC seems just output the bytes as hex string.
    typically you would store bytes in sqlite in a blob (binary) type field.

    Code:
    Sub Button1_Click
        
        
    Dim HexString As String
        HexString =  XorEncode(
    "ABCéè§ê:/%$€")
        
    Log(HexString)
          
        
    Log(XorDecode(HexString))
     
    End Sub

    Sub XorEncode(Source As StringAs String

        
    Dim b As ByteConverter

        
    Dim Bytes() As Byte
        Bytes = Source.GetBytes(
    "UTF8")

        
    Dim i As Int
        
    For i = 0 To Bytes.Length-1
            Bytes(i) = 
    Bit.Xor(Bytes(i),88)
        
    Next

        
    Return b.HexFromBytes(Bytes)

    End Sub

    Sub XorDecode(HexString As StringAs String
     
        
    Dim b As ByteConverter
     
        
    Dim Bytes() As Byte
        Bytes = b.HexToBytes(HexString)
     
        
    Dim i As Int
        
    For i = 0 To Bytes.Length -1
            Bytes(i) = 
    Bit.Xor(Bytes(i),88)
        
    Next

        
    Return BytesToString(Bytes, 0, Bytes.Length, "UTF-8")

    End Sub
     
  9. OliverA

    OliverA Expert Licensed User

    As long as you have an encryption library that can do AES, you can re-implement B4XCipher in PFC/Lazarus. The source (Java) for B4XCipher can be found here https://github.com/AnywhereSoftware...nywheresoftware/b4x/object/B4XEncryption.java.
    That should not matter. Java sees it as signed, but the internal representation (the bit format of the byte) is still what it should be. Just when you try to log the byte with Java, you'll get a signed output. For unsigned output just add 256 to negative values when logging (just add it in the log statement, not directly to the byte).
    If you need string, @MarkusR gave you two options: Base64 and Hex. Base64 will increase the size by about 33% and Hex will double the size of your string. Hex may be faster to produce (you will need to test this), but if you need to read/write data from/to disk or sent it across the network, then the amount of data (less) may be more important (disk and network are way slower than memory. Again test, test, test).
     
  10. luc-dev

    luc-dev Member Licensed User

    Many thanks to @MarkusR and @OliverA for your help!

    I finally managed to have it working (I need further testing but I didn't get any error so far).

    Here is the resulting code in case it can help someone else:

    for B4J:

    Code:
    Sub Button1_Click
        
    Dim aStr1 As String
        
    Dim aStr2 As String
        aStr1 = XorEncode(
    "MyKey""ABCéè§ê:/%$€")
        
    Log(aStr1)
        aStr2 = XorDecode(
    "MyKey", aStr1)
        
    Log(aStr2)
    End Sub

    Sub XorEncode(Key As String, Source As StringAs String
        
    Dim b As ByteConverter
        
    Dim S1() As Byte = Source.GetBytes("UTF-8")
        
    Dim k1() As Byte = Key.GetBytes("UTF-8")
        
    Dim aResult As StringBuilder
        aResult.Initialize
        
    For i = 0 To S1.Length-1
            S1(i) = 
    Bit.Xor(k1(i Mod k1.Length), S1(i))
        
    Next
        
    Return b.HexFromBytes(S1)
    End Sub

    Sub XorDecode(Key As String, Source As StringAs String
        
    Dim b As ByteConverter
        
    Dim aResult As String = ""
        
    Dim S1() As Byte = b.HexToBytes(Source)
        
    Dim k1() As Byte = b.StringToBytes(Key, "UTF-8")
         
        
    For i = 0 To S1.Length -1
            S1(i) = 
    Bit.Xor(k1(i Mod k1.Length), S1(i))
        
    Next
        aResult = 
    BytesToString(S1, 0, S1.Length, "UTF-8")
        
    Return aResult
    End Sub
    For Lazarus or Delphi (to be check for Delphi and UTF-16 Encoding):
    Code:
    function XorEncode2(const Key, Source: string): string;
    var
      i: Integer;
      C: Byte;
    begin
      Result:=
    '';
      for i:=1 to Length(Source) do
        begin
          C:=Byte(Key[
    1 + ((i - 1mod Length(Key))]) xor Byte(Source[i]);
          Result:=Result + (intToHex(C, 
    2));
        
    end;
    end;

    function XorDecode2(
    const Key, Source: string): string;
    var
      i: Integer;
      C: Char;
    begin
      Result:=
    '';
      for i:=0 to Length(Source) div 2 - 1 do
        begin
        C:=
    Chr(StrTointDef('$' + Copy(Source, (i * 2) + 1, 2), Ord(' ')));
        C:=Chr(Byte(Key[1 + (i mod Length(Key))]) xor Byte(C));
        Result:=Result + C;
        
    end;
    end;
    The code for lazarus is merely a simplified copy of the original XorEncode and XorDecode functions from freepascal RTL.

    B4J is very, very fast doing the encoding/decoding (I was quite impressed as it seems to be faster than freepascal)

    Thanks again for this great forum and support!

    Luc
     
    DonManfred and MarkusR like this.
  11. sorex

    sorex Expert Licensed User

    B4J (or JAVA?) doesn't support unsigned bytes.

    the trick I use in some projects is below...

    Code:
    v=Bit.And(bytes(x)+256,255)
     
  12. luc-dev

    luc-dev Member Licensed User

Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice