Java: Base64 Encode a String using a key

40,155

Solution 1

Base64 is not for 'encoding with a key'. It is simply a encoding scheme: you can use Base64 to encrypt and decrypt strings without any extra's. It's just for very (very) basic security usages.

Solution 2

you can xor the data with your key and then base64 encode it.

var key = "mykey";
var mydata = "some long text here";
var output = '';

for (var i = 0, len = mydata.length; i < len; i++) {
   output += String.fromCharCode(mydata.charCodeAt(i) ^ key.charCodeAt(i % key.length));
}

and then you encode 'output' to base64 using some function from somewhere

Solution 3

If you need to encode with Base64 using a key, then actually it is not hard to do this, even if it is not defined in the standard.

Base64 uses an alphabet of 64 symbols. The first 62 symbolss are small and capital letters of English alphabet, plus digits from 0 to 9. The final 2 characters most commonly are + and /, but these can differ between implementation.

So now understand, that when you break your string into bits, and regroup them using 6 bits instead of 8 per symbol, you will alway be able to look up a symbol in your alphabet, because 6 bit numbers have exactly 64 different possible values. Base64 just enumerates symbols from %000000 (0) to 111111 (63). But you could use a key during this symbol lookup. Say your 6 bit number is %000011 (3), thus it would index the 4th symbol in your alphabet. But now you can use your key to modify that index, move it left or right by (for example) the number of positions equal to the ASCII code of your key's character (8 bit number). Whenever your index goes out of range (below 0 or above 63) you just teleport it to the opposite side of the range. And if you moved the index right during encoding, use left direction for decoding (and vice versa). Basically you are scrambling the symbol lookup with a pattern defined by the characters of your key.

There you go, you just use Base64 encoding with a key (rather then first keying the input then encoding). You're welcome.

And since you asked for a code sample, below is a quick sample in Object Pascal, that I wrote. This code could be faster if you first allocate memory for the final string and then write into it, instead of concatenating to the string in a loop, which re-allocates memory every time - but that you can figure out yourself, if you have need for better performance:


const 
      C_ALPHABIG      = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
      C_ALPHASMALL    = 'abcdefghijklmnopqrstuvwxyz';
      C_ALPHA         = C_ALPHABIG+C_ALPHASMALL;
      C_DIGITS        = '0123456789';
      C_SYMBOLS       = '+/';
      C_ALPHABET      = C_ALPHA+C_DIGITS+C_SYMBOLS;

    type 
      TIndexShiftDirection = (isdLeft, isdRight);

      Function ShiftSymbolIndex(const AIndex: integer; const AKey: string; var ACurrentKeyPos: integer; const ADirection: TIndexShiftDirection): integer;
       begin
         Result := AIndex; if(AKey='')then exit;
         if(ACurrentKeyPosLength(AKey))then ACurrentKeyPos := 1;
         if(ADirection=isdRight)
           then begin
                  Result := Result+Ord(AKey[ACurrentKeyPos]);
                  if(Result>64)then Result := Result mod 64;
                  if(Result=0)then Result :=64;
                end
           else begin
                  Result := Result-Ord(AKey[ACurrentKeyPos]);
                  if(Result=Length(AKey))
           then ACurrentKeyPos := 1
           else inc(ACurrentKeyPos);
       end;

      Function  Encode64(const s: string; const Key: string): string;
       var
         i,n,p,k : integer;
         a,b,c,d : byte;
       begin
         Result   := ''; k := 1; if(s='')then exit;
         n := Length(s)div 3;
         if(n>0)then for i:=0 to n-1 do
           begin
             p := (i*3)+1;
             a := (ord(s[p])shr 2); inc(a);
             b := ((ord(s[p])and %00000011)shl 4)+(ord(s[p+1])shr 4); inc(b);
             c := ((ord(s[p+1])and %00001111)shl 2)+(ord(s[p+2])shr 6); inc(c);
             d := ord(s[p+2])and %00111111; inc(d);
           //
             a := ShiftSymbolIndex(a,key,k, isdRight);
             b := ShiftSymbolIndex(b,key,k, isdRight);
             c := ShiftSymbolIndex(c,key,k, isdRight);
             d := ShiftSymbolIndex(d,key,k, isdRight);
           //
             Result := Result
                     + C_ALPHABET[a]
                     + C_ALPHABET[b]
                     + C_ALPHABET[c]
                     + C_ALPHABET[d];
           end;
         n := Length(s)-(n*3);
         if(n=0)then begin {Result := Result+'0';} exit; end;
         case n of
           1: begin
                p := Length(s);
                a := (ord(s[p])shr 2);         inc(a); a := ShiftSymbolIndex(a,key,k, isdRight);
                b := (ord(s[p])and %00000011); inc(b); b := ShiftSymbolIndex(b,key,k, isdRight);
                Result := Result
                        + C_ALPHABET[a]
                        + C_ALPHABET[b]
                        {+ '2'};//if Length(endoced_str)mod 4 = 2, then this case is true
              end;
           2: begin
                p := Length(s)-1;
                a := (ord(s[p])shr 2);
                b := ((ord(s[p])and %00000011)shl 4)+(ord(s[p+1])shr 4);
                c := (ord(s[p+1])and %00001111);
                inc(a); a := ShiftSymbolIndex(a,key,k, isdRight);
                inc(b); b := ShiftSymbolIndex(b,key,k, isdRight);
                inc(c); c := ShiftSymbolIndex(c,key,k, isdRight);
                Result := Result
                        + C_ALPHABET[a]
                        + C_ALPHABET[b]
                        + C_ALPHABET[c]
                        {+ '4'};//if Length(endoced_str)mod 4 = 3, then this case is true
              end;
         end;
       end;

      Function  Decode64(const s: string; const Key: string): string;
       var
         n,i,p,k : integer;
         a,b,c,d : byte;
       begin
         Result := ''; k:=1; if(s='')then exit;
         n := Length(s)div 4;
         if(n>0)then for i:=0 to n-1 do
           begin
             p := (i*4)+1;
             a := Pos(s[p],C_ALPHABET);   a := ShiftSymbolIndex(a,key,k, isdLeft);
             b := Pos(s[p+1],C_ALPHABET); b := ShiftSymbolIndex(b,key,k, isdLeft);
             c := Pos(s[p+2],C_ALPHABET); c := ShiftSymbolIndex(c,key,k, isdLeft);
             d := Pos(s[p+3],C_ALPHABET); d := ShiftSymbolIndex(d,key,k, isdLeft);
             if(a*b*c*d=0)then begin Result := ''; exit; end; //cannot be, if symbols are valid
             Result := Result
                     + chr(((a-1)shl 2) + ((b-1)shr 4))
                     + chr((((b-1)and %001111)shl 4) + ((c-1)shr 2))
                     + chr((((c-1)and %000011)shl 6) + (d-1));
           end;
         n := Length(s)mod 4;
         if(n=0)then exit;
         case n of
           2: begin
                p := Length(s)-1;
                a := Pos(s[p],C_ALPHABET);   a := ShiftSymbolIndex(a,key,k, isdLeft);
                b := Pos(s[p+1],C_ALPHABET); b := ShiftSymbolIndex(b,key,k, isdLeft);
                if(a*b=0)then begin Result := ''; exit; end; //cannot be, if symbols are valid
                Result := Result
                        + chr(((a-1)shl 2) + (b-1));
              end;
           3: begin
                p := Length(s)-2;
                a := Pos(s[p],C_ALPHABET);
                b := Pos(s[p+1],C_ALPHABET);
                c := Pos(s[p+2],C_ALPHABET);
                if(a*b*c=0)
                  then begin Result := ''; exit; end; //cannot be, if symbols are valid
                a := ShiftSymbolIndex(a,key,k, isdLeft);
                b := ShiftSymbolIndex(b,key,k, isdLeft);
                c := ShiftSymbolIndex(c,key,k, isdLeft);
                Result := Result
                        + chr(((a-1)shl 2) + ((b-1)shr 4))
                        + chr((((b-1)and %001111)shl 4) + (c-1));
              end;
           else Result := '';
         end;
       end;  

Note the function ShiftSymbolIndex - this is the symbol lookup scrambler, it can either move symbol index right, or left. I use right in the encoder, and left in the encoder, but it's all up to you. If you skip the key argument in either Encode64 or Decode64 function (or if you pass an empty string key), then you will end up with a default Base64 encoding/decoding.

Also, this encoder does not append padding ("=" characters) to the base64 encoded string. The padding is not needed to decode, unless your decoder works in a strict mode (this encoder isn't) - but that, you can figure out yourself.

Share:
40,155
Abhishek
Author by

Abhishek

Master student at Georgia Tech. Android Developer. Interest in User Experience. Weekly online programming competitions. Entrepreneur.

Updated on August 19, 2022

Comments

  • Abhishek
    Abhishek over 1 year

    Hi I have data and a key (both strings). The data needs to be encode using the key using Base64. Can some one give me a sample code.

    • Admin
      Admin almost 13 years
      One doesn't base64 encode with a "key". It (base64) is an encoding scheme, not an encryption algorithm. That being said, I'm confused with that the real goal is - perhaps the title is very badly chosen.
  • SyntaxT3rr0r
    SyntaxT3rr0r almost 13 years
    +1 to you but it may be that the OP wants both to encode using some 'key' (whatever he means by that: a public key from a PKCS or a symmetric key etc.) and then encode the result using Base64.