MoreBeerMorePower

Power Platform中心だけど、ノーコード/ローコード系を書いてます。

Handling base32 string in Power Apps

Base32 is much less common than Base64, so Power Apps/Power Automate don't have capabilities to handle it.

Recently, Base32 encoded string is used in New Zealand COVID passport, and it is provided as QR code.

Ref: New Zealand Covid Pass Specification

In this post, I will show how conversion between different bases can be achieved with Power Apps, using Base32 as an example.

Conversion logic : Base32 -> Base64

Once Base32 string has been converted into Base64, Power Automate has native capability to handle it.

Below figure shows the logic of conversion base32 to base64, which can be realised in Power Apps :

f:id:mofumofu_dance:20211223173535p:plain

For any bases, converting into binary representation is good approach as first step not only in Power Apps. To achieve this, I often use Conversion table including (binary)-(character in some base) pairs, for base32, it is written as

    Table(
        {b32:"A",bin:"00000"},
        {b32:"B",bin:"00001"},
        {b32:"C",bin:"00010"},
        {b32:"D",bin:"00011"},
        {b32:"E",bin:"00100"},
        {b32:"F",bin:"00101"},
        {b32:"G",bin:"00110"},
        {b32:"H",bin:"00111"},
        {b32:"I",bin:"01000"},
        {b32:"J",bin:"01001"},
        {b32:"K",bin:"01010"},
        {b32:"L",bin:"01011"},
        {b32:"M",bin:"01100"},
        {b32:"N",bin:"01101"},
        {b32:"O",bin:"01110"},
        {b32:"P",bin:"01111"},
        {b32:"Q",bin:"10000"},
        {b32:"R",bin:"10001"},
        {b32:"S",bin:"10010"},
        {b32:"T",bin:"10011"},
        {b32:"U",bin:"10100"},
        {b32:"V",bin:"10101"},
        {b32:"W",bin:"10110"},
        {b32:"X",bin:"10111"},
        {b32:"Y",bin:"11000"},
        {b32:"Z",bin:"11001"},
        {b32:"2",bin:"11010"},
        {b32:"3",bin:"11011"},
        {b32:"4",bin:"11100"},
        {b32:"5",bin:"11101"},
        {b32:"6",bin:"11110"},
        {b32:"7",bin:"11111"})

Now convert from the resulting binary representation to some other base. Again, I will use the same conversion table between binary and other base (base64).

    Table(
        {b64:"A",bin:"000000"},
        {b64:"B",bin:"000001"},
        {b64:"C",bin:"000010"},
        {b64:"D",bin:"000011"},
        {b64:"E",bin:"000100"},
        {b64:"F",bin:"000101"},
        {b64:"G",bin:"000110"},
        {b64:"H",bin:"000111"},
        {b64:"I",bin:"001000"},
        {b64:"J",bin:"001001"},
        {b64:"K",bin:"001010"},
        {b64:"L",bin:"001011"},
        {b64:"M",bin:"001100"},
        {b64:"N",bin:"001101"},
        {b64:"O",bin:"001110"},
        {b64:"P",bin:"001111"},
        {b64:"Q",bin:"010000"},
        {b64:"R",bin:"010001"},
        {b64:"S",bin:"010010"},
        {b64:"T",bin:"010011"},
        {b64:"U",bin:"010100"},
        {b64:"V",bin:"010101"},
        {b64:"W",bin:"010110"},
        {b64:"X",bin:"010111"},
        {b64:"Y",bin:"011000"},
        {b64:"Z",bin:"011001"},
        {b64:"a",bin:"011010"},
        {b64:"b",bin:"011011"},
        {b64:"c",bin:"011100"},
        {b64:"d",bin:"011101"},
        {b64:"e",bin:"011110"},
        {b64:"f",bin:"011111"},
        {b64:"g",bin:"100000"},
        {b64:"h",bin:"100001"},
        {b64:"i",bin:"100010"},
        {b64:"j",bin:"100011"},
        {b64:"k",bin:"100100"},
        {b64:"l",bin:"100101"},
        {b64:"m",bin:"100110"},
        {b64:"n",bin:"100111"},
        {b64:"o",bin:"101000"},
        {b64:"p",bin:"101001"},
        {b64:"q",bin:"101010"},
        {b64:"r",bin:"101011"},
        {b64:"s",bin:"101100"},
        {b64:"t",bin:"101101"},
        {b64:"u",bin:"101110"},
        {b64:"v",bin:"101111"},
        {b64:"w",bin:"110000"},
        {b64:"x",bin:"110001"},
        {b64:"y",bin:"110010"},
        {b64:"z",bin:"110011"},
        {b64:"0",bin:"110100"},
        {b64:"1",bin:"110101"},
        {b64:"2",bin:"110110"},
        {b64:"3",bin:"110111"},
        {b64:"4",bin:"111000"},
        {b64:"5",bin:"111001"},
        {b64:"6",bin:"111010"},
        {b64:"7",bin:"111011"},
        {b64:"8",bin:"111100"},
        {b64:"9",bin:"111101"},
        {b64:"+",bin:"111110"},
        {b64:"/",bin:"111111"}
    )

More specifically, the binary number is divided into six characters, each of which is LookUp from the table above.

Finally, perform padding right with "=" using formula below

b64string & Left("====",Mod(4-Mod(Len( b64string ),4),4))

Power Apps formula

Power Apps formula will be lengthly due to two conversion tables but structure is rather simple.

With({
    InputB32:"JBSWY3DPEBLW64TMMQ======",
    B32ToBin:
    Table(
        {b32:"A",bin:"00000"},
        {b32:"B",bin:"00001"},
        {b32:"C",bin:"00010"},
        {b32:"D",bin:"00011"},
        {b32:"E",bin:"00100"},
        {b32:"F",bin:"00101"},
        {b32:"G",bin:"00110"},
        {b32:"H",bin:"00111"},
        {b32:"I",bin:"01000"},
        {b32:"J",bin:"01001"},
        {b32:"K",bin:"01010"},
        {b32:"L",bin:"01011"},
        {b32:"M",bin:"01100"},
        {b32:"N",bin:"01101"},
        {b32:"O",bin:"01110"},
        {b32:"P",bin:"01111"},
        {b32:"Q",bin:"10000"},
        {b32:"R",bin:"10001"},
        {b32:"S",bin:"10010"},
        {b32:"T",bin:"10011"},
        {b32:"U",bin:"10100"},
        {b32:"V",bin:"10101"},
        {b32:"W",bin:"10110"},
        {b32:"X",bin:"10111"},
        {b32:"Y",bin:"11000"},
        {b32:"Z",bin:"11001"},
        {b32:"2",bin:"11010"},
        {b32:"3",bin:"11011"},
        {b32:"4",bin:"11100"},
        {b32:"5",bin:"11101"},
        {b32:"6",bin:"11110"},
        {b32:"7",bin:"11111"}),
    B64ToBin:
    Table(
        {b64:"A",bin:"000000"},
        {b64:"B",bin:"000001"},
        {b64:"C",bin:"000010"},
        {b64:"D",bin:"000011"},
        {b64:"E",bin:"000100"},
        {b64:"F",bin:"000101"},
        {b64:"G",bin:"000110"},
        {b64:"H",bin:"000111"},
        {b64:"I",bin:"001000"},
        {b64:"J",bin:"001001"},
        {b64:"K",bin:"001010"},
        {b64:"L",bin:"001011"},
        {b64:"M",bin:"001100"},
        {b64:"N",bin:"001101"},
        {b64:"O",bin:"001110"},
        {b64:"P",bin:"001111"},
        {b64:"Q",bin:"010000"},
        {b64:"R",bin:"010001"},
        {b64:"S",bin:"010010"},
        {b64:"T",bin:"010011"},
        {b64:"U",bin:"010100"},
        {b64:"V",bin:"010101"},
        {b64:"W",bin:"010110"},
        {b64:"X",bin:"010111"},
        {b64:"Y",bin:"011000"},
        {b64:"Z",bin:"011001"},
        {b64:"a",bin:"011010"},
        {b64:"b",bin:"011011"},
        {b64:"c",bin:"011100"},
        {b64:"d",bin:"011101"},
        {b64:"e",bin:"011110"},
        {b64:"f",bin:"011111"},
        {b64:"g",bin:"100000"},
        {b64:"h",bin:"100001"},
        {b64:"i",bin:"100010"},
        {b64:"j",bin:"100011"},
        {b64:"k",bin:"100100"},
        {b64:"l",bin:"100101"},
        {b64:"m",bin:"100110"},
        {b64:"n",bin:"100111"},
        {b64:"o",bin:"101000"},
        {b64:"p",bin:"101001"},
        {b64:"q",bin:"101010"},
        {b64:"r",bin:"101011"},
        {b64:"s",bin:"101100"},
        {b64:"t",bin:"101101"},
        {b64:"u",bin:"101110"},
        {b64:"v",bin:"101111"},
        {b64:"w",bin:"110000"},
        {b64:"x",bin:"110001"},
        {b64:"y",bin:"110010"},
        {b64:"z",bin:"110011"},
        {b64:"0",bin:"110100"},
        {b64:"1",bin:"110101"},
        {b64:"2",bin:"110110"},
        {b64:"3",bin:"110111"},
        {b64:"4",bin:"111000"},
        {b64:"5",bin:"111001"},
        {b64:"6",bin:"111010"},
        {b64:"7",bin:"111011"},
        {b64:"8",bin:"111100"},
        {b64:"9",bin:"111101"},
        {b64:"+",bin:"111110"},
        {b64:"/",bin:"111111"}
    )
},
With({
    BinRep:Concat(AddColumns(Split(InputB32,""),"Bin",LookUp(B32ToBin,b32=Result).bin),Bin,"")//Convert base32 string to binary representation
    },
With({b64string:Concat(
    Sequence(
        RoundUp(Len(BinRep)/6,0),0),
        LookUp(
            B64ToBin,
            bin=Mid(BinRep&Left("000000",6-Mod(Len(BinRep),6)),6*Value+1,6) //Left("000000"....) is padding right with zero
        ).b64&"", 
        ""
    )},
     b64string&Left("====",Mod(4-Mod(Len(b64string),4),4))//Convert binary to hexadecimal
)
))

This returns SGVsbG8gV29ybGQ= (Base64-ed Hellow World).

Other conversion table

For NZ COVID pass, Base32 should be converted to Hexadecimal string, and it will be achieved with conversion table for binary->hexadecimal:

    Table(
        {hex:"0",bin:"0000"},
        {hex:"1",bin:"0001"},
        {hex:"2",bin:"0010"},
        {hex:"3",bin:"0011"},
        {hex:"4",bin:"0100"},
        {hex:"5",bin:"0101"},
        {hex:"6",bin:"0110"},
        {hex:"7",bin:"0111"},
        {hex:"8",bin:"1000"},
        {hex:"9",bin:"1001"},
        {hex:"a",bin:"1010"},
        {hex:"b",bin:"1011"},
        {hex:"c",bin:"1100"},
        {hex:"d",bin:"1101"},
        {hex:"e",bin:"1110"},
        {hex:"f",bin:"1111"}
    )

f:id:mofumofu_dance:20211223175516p:plain