SBPEM.pas
上传用户:qdyddl
上传日期:2014-04-21
资源大小:11640k
文件大小:31k
- (******************************************************)
- (* *)
- (* EldoS SecureBlackbox Library *)
- (* *)
- (* Copyright (c) 2002-2007 EldoS Corporation *)
- (* http://www.secureblackbox.com *)
- (* *)
- (******************************************************)
- {$I SecBbox.inc}
- unit SBPEM;
- interface
- uses
- SysUtils,
- Classes,
- {$ifndef CLX_USED}
- Windows,
- {$else}
- Libc,
- {$endif}
- SBUtils;
- const
- PEM_DECODE_RESULT_OK = Integer(0);
- PEM_DECODE_RESULT_INVALID_FORMAT = Integer($1D01);
- PEM_DECODE_RESULT_INVALID_PASSPHRASE = Integer($1D02);
- PEM_DECODE_RESULT_NOT_ENOUGH_SPACE = Integer($1D03);
- PEM_DECODE_RESULT_UNKNOWN_CIPHER = Integer($1D04);
- type
- TSBBase64Context = record
- Tail : array [0..3] of byte;
- TailBytes : integer;
- LineWritten : integer;
- LineSize : integer;
- fEOL : array [0..3] of byte;
- EOLSize : integer;
- OutBuf : array [0..3] of byte;
- EQUCount : integer;
- end;
- TElPEMProcessor = class(TSBComponentBase)
- protected
- FHeader : string;
- FPassphrase: string;
- public
- function PEMEncode(const InBuffer : ByteArray; var OutBuffer : ByteArray; Encrypt : boolean) : boolean; overload;
- function PEMDecode(const InBuffer : ByteArray; var OutBuffer : ByteArray) : integer; overload;
- function PEMEncode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
- var OutSize : integer; Encrypt : boolean) : boolean; overload;
- function PEMDecode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
- var OutSize : integer) : integer; overload;
- published
- property Header : string read FHeader write FHeader;
- property Passphrase: string read FPassphrase write FPassphrase;
- end;
- function Encode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
- var OutSize : integer; const Header : string; Encrypt : boolean;
- const PassPhrase : string) : boolean;
- function Decode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
- const PassPhrase : string; var OutSize : integer; var Header : string) : integer;
- function IsBase64UnicodeSequence(Buffer : pointer; Size : integer) : boolean;
- function IsBase64Sequence(Buffer : pointer; Size : integer) : boolean;
- function B64InitializeEncoding(var Ctx : TSBBase64Context; LineSize : integer;
- fEOL : TSBEOLMarker) : boolean;
- function B64InitializeDecoding(var Ctx : TSBBase64Context) : boolean;
- function B64Encode(var Ctx : TSBBase64Context; Buffer : pointer; Size : integer;
- OutBuffer : pointer; var OutSize : integer) : boolean;
- function B64Decode(var Ctx : TSBBase64Context; Buffer : pointer; Size : integer;
- OutBuffer: pointer; var OutSize : integer) : boolean;
- function B64FinalizeEncoding(var Ctx : TSBBase64Context;
- OutBuffer : pointer; var OutSize : integer) : boolean;
- function B64FinalizeDecoding(var Ctx : TSBBase64Context;
- OutBuffer : pointer; var OutSize : integer) : boolean;
- type
- EPEMError = class(ESecureBlackboxError);
- procedure RaisePEMError(ErrorCode : integer);
- implementation
- uses
- {$ifndef SBB_NO_DES}
- SBDES,
- SB3DES,
- {$endif}
- SBConstants,
- SBMath,
- SBMD
- ;
- resourcestring
- sInvalidPEMFormat = 'Invalid file format (possibly not a PEM?)';
- sIncorrectPassphrase = 'Incorrect password';
- sNotEnoughBufferSpace = 'Not enough buffer space';
- sUnknownCipher = 'Unsupported data encryption method';
- procedure RaisePEMError(ErrorCode : integer);
- begin
- case ErrorCode of
- PEM_DECODE_RESULT_INVALID_FORMAT : raise EPEMError.Create(sInvalidPEMFormat, ErrorCode{$ifndef HAS_DEF_PARAMS}{$ifndef FPC}, 0{$endif}{$endif});
- PEM_DECODE_RESULT_INVALID_PASSPHRASE : raise EPEMError.Create(sIncorrectPassphrase, ErrorCode{$ifndef HAS_DEF_PARAMS}{$ifndef FPC}, 0{$endif}{$endif});
- PEM_DECODE_RESULT_NOT_ENOUGH_SPACE : raise EPEMError.Create(sNotEnoughBufferSpace, ErrorCode{$ifndef HAS_DEF_PARAMS}{$ifndef FPC}, 0{$endif}{$endif});
- PEM_DECODE_RESULT_UNKNOWN_CIPHER : raise EPEMError.Create(sUnknownCipher, ErrorCode{$ifndef HAS_DEF_PARAMS}{$ifndef FPC}, 0{$endif}{$endif});
- else
- exit;
- end;
- end;
- (*
- {$ifndef SBB_NO_DES}
- procedure ConvertPassPhraseToKey(const PassPhrase : string; var Key : TDESKey;
- var IV : TDESBuffer);
- var
- MD1, MD2, MD3 : TMessageDigest128;
- {$ifdef DELPHI_NET}
- TmpBuf : ByteArray;
- TmpStr : AnsiString;
- CnvPwd : ByteArray;
- {$endif}
- begin
- {$ifdef DELPHI_NET}
- CnvPwd := Encoding.ASCII.GetBytes(PassPhrase);
- // TmpStr := CloneBuffer(CnvPwd);
- // SetLength(TmpBuf, Length(TmpStr));
- // if Length(TmpBuf) > 0 then
- // Move(TmpStr, 0, TmpBuf, 0, Length(TmpBuf));
- // MD1 := HashMD5(TmpBuf, Length(TmpBuf));
- MD1 := HashMD5(CnvPwd, Length(CnvPwd));
- {$ifndef CHROME}
- TmpStr := PassPhrase + base64Pad + PassPhrase;
- {$else}
- TmpStr := SBConcatBuffers(CnvPwd, base64PadByteArray);
- TmpStr := SBConcatBuffers(TmpStr, CnvPwd);
- {$endif}
- {$ifndef CHROME}
- SetLength(TmpBuf, Length(TmpStr));
- if Length(TmpBuf) > 0 then
- Move(TmpStr, 0, TmpBuf, 0, Length(TmpBuf));
- {$else}
- TmpBuf := TmpStr;
- {$endif}
- MD2 := HashMD5(TmpBuf, Length(TmpBuf));
- {$else}
- MD1 := HashMD5(PassPhrase);
- MD2 := HashMD5(PassPhrase + base64Pad + PassPhrase);
- {$endif}
- MD3.A := MD1.A xor MD2.A;
- MD3.B := MD1.B xor MD2.B;
- MD3.C := MD1.C xor MD2.C;
- MD3.D := MD1.D xor MD2.D;
- {$ifdef DELPHI_NET}
- TmpBuf := StructureToByteArray(MD3);
- Move(TmpBuf, 0, Key, 0, 8);
- Move(TmpBuf, 8, IV, 0, 8);
- {$else}
- Move(PByteArray(@MD3)[0], Key[0], 8);
- Move(PByteArray(@MD3)[8], IV[0], 8);
- {$endif}
- end;
- {$endif}
- *)
- function BytesToKey(const Passphrase : BufferType; const Salt : BufferType; Needed: integer) : BufferType;
- var
- Context : TMD5Context;
- AM : integer;
- MDS, I, KeyCount : integer;
- M128 : TMessageDigest128;
- KeyPtr : ^byte;
- begin
- AM := 0;
- MDS := 0;
- SetLength(Result, Needed);
- KeyPtr := @Result[1];
- KeyCount := Needed;
- while true do
- begin
- SBMD.InitializeMD5(Context);
- Inc(AM);
- if (AM <> 0) then
- SBMD.HashMD5(Context, @M128, MDS);
- SBMD.HashMD5(Context, @Passphrase[1], Length(Passphrase));
- if Length(Salt) <> 0 then
- SBMD.HashMD5(Context, @Salt[1], Length(Salt));
- M128 := SBMD.FinalizeMD5(Context);
- I := 0;
- MDS := 16;
- while true do
- begin
- if KeyCount = 0 then
- Break;
- if I = MDS then
- Break;
- KeyPtr^ := PByteArray(@M128)[I];
- Inc(KeyPtr);
- Dec(KeyCount);
- Inc(I);
- end;
- if KeyCount = 0 then
- Break;
- end;
- end;
- function Encode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
- var OutSize : integer; const Header : string; Encrypt : boolean;
- const PassPhrase : string) : boolean;
- var
- InBuf,
- Buf : ByteArray;
- Sz, I, EstSize : integer;
- OutSz : cardinal;
- PEMBeginLine, PEMEndLine, PEMHeaders : AnsiString;
- {$ifndef SBB_NO_DES}
- DESKey : T3DESKey;
- DESIV : T3DESBuffer;
- Ctx : T3DESContext;
- {$endif}
- Key, Salt : BufferType;
- //RandCtx : TRC4RandomContext;
- begin
- Result := true;
- {$ifndef SBB_NO_DES}
- if Encrypt then
- begin
- SetLength(Salt, 8);
- //LRC4Init(RandCtx);
- for I := 1 to 8 do
- Salt[I] := Chr(SBRndGenerate(256){LRC4RandomByte(RandCtx)});
- Key := BytesToKey(Passphrase, Salt, 24);
- Move(Key[1], DESKey[0], 24);
- Move(Salt[1], DESIV[0], 8);
- PEMHeaders := 'Proc-Type: 4,ENCRYPTED'#$0A;
- PEMHeaders := PEMHeaders + 'DEK-Info: DES-EDE3-CBC,';
- for I := 0 to 7 do
- PEMHeaders := PEMHeaders + IntToHex(DESIV[I], 2);
- PEMHeaders := PEMHeaders + #$0A#$0A;
- SetLength(InBuf, (InSize div 8 + 1) * 8);
- Move(InBuffer^, InBuf[0], InSize);
- FillChar(InBuf[InSize], Length(InBuf) - InSize, Chr(Length(InBuf) - InSize));
- SB3DES.InitializeEncryptionCBC(Ctx, DESKey, DESIV);
- OutSz := Length(InBuf);
- SB3DES.EncryptCBC(Ctx, @InBuf[0], Length(InBuf), @InBuf[0], OutSz);
- SetLength(Buf, Length(InBuf) * 2);
- Sz := Length(InBuf) * 2;
- if not Base64Encode(@InBuf[0], Length(InBuf), @Buf[0], Sz) then
- begin
- Result := false;
- Exit;
- end;
- end
- else
- {$endif}
- begin
- SetLength(Buf, InSize * 2);
- Sz := InSize * 2;
- if not Base64Encode(InBuffer, InSize, @Buf[0], Sz) then
- begin
- Result := false;
- Exit;
- end;
- PEMHeaders := '';
- end;
-
- PEMBeginLine := BeginLine + Header + Line + #$0A + PEMHeaders;
- PEMEndLine := EndLine + Header + Line + #$0A;
- { Checking whether we have enough space in buffer }
- EstSize := Length(PEMBeginLine) + Length(PEMEndLine) + Sz;
- if (OutSize < EstSize) then
- begin
- OutSize := EstSize;
- Result := false;
- Exit;
- end;
- Move(PEMBeginLine[1], PByteArray(OutBuffer)[0], Length(PEMBeginLine));
- SetLength(Buf, Sz);
- Move(Buf[0], PByteArray(OutBuffer)[Length(PEMBeginLine)], Length(Buf));
- Move(PEMEndLine[1], PByteArray(OutBuffer)[Length(PEMBeginLine) + Length(Buf)],
- Length(PEMEndLine));
- OutSize := EstSize; //Length(PEMBeginLine) + Length(Buf) + Length(PEMEndLine);
- SetLength(Buf, 0);
- end;
- function HexStringToBuffer(const HexStr : string) : BufferType;
- function HexBytesToSym(B1, B2 : char) : byte;
- var
- P1, P2 : byte;
- begin
- if (B1 >= 'A') and (B1 <= 'F') then
- P1 := Ord(B1) - Ord('A') + 10
- else if (B1 >= '0') and (B1 <= '9') then
- P1 := Ord(B1) - Ord('0')
- else
- P1 := 0;
- if (B2 >= 'A') and (B2 <= 'F') then
- P2 := Ord(B2) - Ord('A') + 10
- else if (B2 >= '0') and (B2 <= '9') then
- P2 := Ord(B2) - Ord('0')
- else
- P2 := 0;
- Result := (P1 shl 4) or P2;
- end;
- var
- I : integer;
- begin
- if Length(HexStr) mod 2 <> 0 then
- SetLength(Result, 0)
- else
- begin
- I := 1;
- SetLength(Result, Length(HexStr) div 2);
- while I <= Length(Result) do
- begin
- Result[I] := Chr(HexBytesToSym(HexStr[I * 2 - 1], HexStr[I * 2]));
- Inc(I);
- end;
- end;
- end;
- function Decode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
- const PassPhrase : string; var OutSize : integer; var Header : string) : integer;
- var
- S1, S2 : BufferType;
- S, Headers, Tmp : String;
- I, HeaderEnd, Res, Cipher, I1, I2, I3 : integer;
- {$ifndef SBB_NO_DES}
- DESIV : TDESBuffer;
- DESEDE3IV : T3DESBuffer;
- DESKey : TDESKey;
- DESEDE3Key : T3DESKey;
- Ctx : TDESContext;
- CtxEDE : T3DESContext;
- {$endif}
- Sz : cardinal;
- EolLen : integer;
- begin
- Result := PEM_DECODE_RESULT_OK;
- SetLength(S, InSize);
- Move(InBuffer^, S[1], InSize);
- if Pos(BeginLine, S) <= 0 then
- begin
- Result := PEM_DECODE_RESULT_INVALID_FORMAT;
- Exit;
- end;
- I1 := Pos(#13#13#10, S);
- I2 := Pos(#13#10, S);
- I3 := Pos(#10, S);
- if I1 = 0 then I1 := $7FFFFFFF;
- if I2 = 0 then I2 := $7FFFFFFF;
- if I3 = 0 then I3 := $7FFFFFFF;
- I := Min(Min(I1, I2), I3);
- if I = I1 then
- EolLen := 3
- else if I = I2 then
- EolLen := 2
- else
- EolLen := 1;
- if I = $7FFFFFFF then
- begin
- Result := PEM_DECODE_RESULT_INVALID_FORMAT;
- OutSize := 0;
- Exit;
- end;
- Header := Copy(S, Length(BeginLine) + 1, I - Length(Line) - Length(BeginLine) - 1);
- S := Copy(S, I + EolLen, Length(S));
- if Pos('Proc-Type', S) = 1 then
- begin
- HeaderEnd := Pos(#$0D#$0D#$0A#$0D#$0D#$0A, S);
- if HeaderEnd = 0 then
- begin
- HeaderEnd := Pos(#$0A#$0A, S);
- if HeaderEnd = 0 then
- HeaderEnd := Pos(#$0D#$0A#$0D#$0A, S);
- end;
- Headers := Copy(S, 1, HeaderEnd - 1);
-
- while Pos('DEK-Info:', Headers) > 1 do
- begin
- I := Pos(#$0A, Headers);
- Headers := Copy(Headers, I + 1, Length(Headers));
- end;
- if Pos('DEK-Info:', Headers) = 1 then
- begin
- I := Pos(#$0A, Headers);
- if I > 0 then
- Headers := Copy(Headers, 1, I - 1);
- I := Pos(' ', Headers);
- Headers := Copy(Headers, I + 1, Length(Headers));
- I := Pos(',', Headers);
- Tmp := Copy(Headers, 1, I - 1);
- {$ifndef SBB_NO_DES}
- if CompareStr('DES-CBC', Tmp) = integer(0) then
- Cipher := SB_ALGORITHM_CNT_DES
- else
- if CompareStr('DES-EDE3-CBC', Tmp) = integer(0) then
- Cipher := SB_ALGORITHM_CNT_3DES
- else
- {$endif}
- begin
- Result := PEM_DECODE_RESULT_UNKNOWN_CIPHER;
- Exit;
- end;
-
- Tmp := Copy(Headers, I + 1, Length(Headers));
- S1 := HexStringToBuffer(Tmp);
- {$ifndef SBB_NO_DES}
- if Cipher = SB_ALGORITHM_CNT_DES then
- begin
- S2 := BytesToKey(Passphrase, S1, 8);
- Move(S2[1], DESKey[0], 8);
- Move(S1[1], DESIV[0], 8);
- end
- else
- if Cipher = SB_ALGORITHM_CNT_3DES then
- begin
- S2 := BytesToKey(Passphrase, S1, 24);
- Move(S2[1], DESEDE3Key[0], 24);
- Move(S1[1], DESEDE3IV[0], 8);
- end;
- {$endif}
- Headers := '';
- {$ifndef SBB_NO_DES}
- for I := 0 to 7 do
- if Cipher = SB_ALGORITHM_CNT_DES then
- Headers := Headers + IntToHex(DESIV[I], 2)
- else
- if Cipher = SB_ALGORITHM_CNT_3DES then
- Headers := Headers + IntToHex(DESEDE3IV[I], 2);
- {$endif}
- if CompareStr(Headers, Tmp) <> integer(0) then
- begin
- Result := PEM_DECODE_RESULT_INVALID_PASSPHRASE;
- Exit;
- end;
- I := Pos(EndLine, S);
- Res := Base64Decode(@S[HeaderEnd + 2], I - HeaderEnd - 2, OutBuffer, OutSize);
- if Res = 0 then
- begin
- {$ifndef SBB_NO_DES}
- if Cipher = SB_ALGORITHM_CNT_DES then
- begin
- SBDES.InitializeDecryptionCBC(Ctx, DESKey, DESIV);
- Sz := OutSize;
- SBDES.DecryptCBC(Ctx, OutBuffer, OutSize, OutBuffer, Sz);
- end
- else
- if Cipher = SB_ALGORITHM_CNT_3DES then
- begin
- SB3DES.InitializeDecryptionCBC(CtxEDE, DESEDE3Key, DESEDE3IV);
- Sz := OutSize;
- SB3DES.DecryptCBC(CtxEDE, OutBuffer, OutSize, OutBuffer, Sz);
- end;
- {$endif}
- if PByteArray(OutBuffer)[Sz - 1] > 8 then
- begin
- Result := PEM_DECODE_RESULT_INVALID_PASSPHRASE;
- Exit;
- end;
- OutSize := Sz - PByteArray(OutBuffer)[Sz - 1];
- if OutSize < 0 then
- begin
- Result := PEM_DECODE_RESULT_INVALID_PASSPHRASE;
- Exit;
- end;
- Result := PEM_DECODE_RESULT_OK;
- end
- else
- if Res = BASE64_DECODE_NOT_ENOUGH_SPACE then
- begin
- Result := PEM_DECODE_RESULT_NOT_ENOUGH_SPACE;
- Exit;
- end
- else
- if Res = BASE64_DECODE_INVALID_CHARACTER then
- begin
- Result := PEM_DECODE_RESULT_INVALID_FORMAT;
- Exit;
- end;
- end
- else
- begin
- Result := PEM_DECODE_RESULT_INVALID_FORMAT;
- Exit;
- end;
- end
- else
- begin
- I := Pos(EndLine, S);
- Result := Base64Decode(@S[1], I - 1, OutBuffer, OutSize);
- case Result of
- BASE64_DECODE_OK:
- Result := PEM_DECODE_RESULT_OK;
- BASE64_DECODE_NOT_ENOUGH_SPACE:
- Result := PEM_DECODE_RESULT_NOT_ENOUGH_SPACE
- else
- Result := PEM_DECODE_RESULT_INVALID_FORMAT;
- end;
- end;
- end;
- function TElPEMProcessor.PEMEncode(const InBuffer : ByteArray; var OutBuffer : ByteArray; Encrypt : boolean) : boolean;
- var OutSize : integer;
- begin
- OutSize := 0;
- Encode(InBuffer, Length(InBuffer), nil, OutSize, FHeader, Encrypt, FPassphrase);
- SetLength(OutBuffer, OutSize);
- result := Encode(InBuffer, Length(InBuffer), OutBuffer, OutSize, FHeader, Encrypt, FPassphrase);
- if result then
- begin
- if (Length(OutBuffer) <> OutSize) then
- SetLength(OutBuffer, OutSize);
- end
- else
- SetLength(OutBuffer, 0);
- end;
- function TElPEMProcessor.PEMEncode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
- var OutSize : integer; Encrypt : boolean) : boolean;
- begin
- result := Encode(InBuffer, InSize, OutBuffer, OutSize, FHeader, Encrypt, FPassphrase);
- end;
- function TElPEMProcessor.PEMDecode(const InBuffer : ByteArray; var OutBuffer : ByteArray) : integer;
- var OutSize : integer;
- begin
- OutSize := 0;
- result := Decode(InBuffer, Length(InBuffer), nil, FPassphrase, OutSize, FHeader);
- if result = PEM_DECODE_RESULT_NOT_ENOUGH_SPACE then
- begin
- SetLength(OutBuffer, OutSize);
- result := Decode(InBuffer, Length(InBuffer), OutBuffer, FPassphrase, OutSize, FHeader);
- if result = 0 then
- begin
- if (Length(OutBuffer) <> OutSize) then
- SetLength(OutBuffer, OutSize);
- end
- else
- SetLength(OutBuffer, 0);
- end
- else
- SetLength(OutBuffer, 0);
- end;
- function TElPEMProcessor.PEMDecode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
- var OutSize : integer) : integer;
- begin
- result := Decode(InBuffer, InSize, OutBuffer, FPassphrase, OutSize, FHeader);
- end;
- function IsBase64UnicodeSequence(Buffer : pointer; Size : integer) : boolean;
- var i : integer;
- eqcnt : integer;
- begin
- result := true;
- i := 0;
- eqcnt := 0;
- while i < Size do
- begin
- if PByteArray(Buffer)[i + 1] <> 0 then
- begin
- result := false;
- exit;
- end;
- case Char(PByteArray(Buffer)[i]) of
- 'A' .. 'Z',
- 'a' .. 'z',
- '0' .. '9',
- '+', '/':
- begin
- if eqcnt = 0 then
- begin
- inc(i, 2);
- continue;
- end
- else
- begin
- result := false;
- break;
- end;
- end;
- #0:
- begin
- if eqcnt > 0 then
- begin
- inc(i, 2);
- continue;
- end
- else
- begin
- result := false;
- break;
- end;
- end;
- #13, #10:
- begin
- inc(i, 2);
- continue;
- end;
- '=':
- begin
- if eqcnt < 2 then
- begin
- inc(eqcnt);
- inc(i, 2);
- Continue;
- end
- else
- begin
- result := false;
- exit;
- end;
- end;
- else
- begin
- result := false;
- exit;
- end;
- end;
- end;
- end;
- function IsBase64Sequence(Buffer : pointer; Size : integer) : boolean;
- var i : integer;
- eqcnt : integer;
- begin
- result := true;
- eqcnt := 0;
- for i := 0 to Size - 1 do
- begin
- case Char(PByteArray(Buffer)[i]) of
- 'A' .. 'Z',
- 'a' .. 'z',
- '0' .. '9',
- '+', '/':
- begin
- if eqcnt = 0 then
- continue
- else
- begin
- result := false;
- break;
- end;
- end;
- #0:
- begin
- if eqcnt > 0 then
- begin
- continue;
- end
- else
- begin
- result := false;
- break;
- end;
- end;
- #13, #10:
- begin
- continue;
- end;
- '=':
- begin
- if eqcnt < 2 then
- begin
- inc(eqcnt);
- Continue;
- end
- else
- begin
- result := false;
- exit;
- end;
- end;
- else
- begin
- result := false;
- exit;
- end;
- end;
- end;
- end;
- { Base64 processing routines }
- const
- Base64Symbols : array [0..63] of byte =
- (
- $41, $42, $43, $44, $45, $46, $47, $48, $49, $4A, $4B, $4C, $4D, $4E, $4F, $50,
- $51, $52, $53, $54, $55, $56, $57, $58, $59, $5A, $61, $62, $63, $64, $65, $66,
- $67, $68, $69, $6A, $6B, $6C, $6D, $6E, $6F, $70, $71, $72, $73, $74, $75, $76,
- $77, $78, $79, $7A, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $2B, $2F
- );
- Base64Values : array [0..255] of byte =
- (
- $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FE, $FE, $FF, $FF, $FE, $FF, $FF,
- $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
- $FE, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $3E, $FF, $FF, $FF, $3F,
- $34, $35, $36, $37, $38, $39, $3A, $3B, $3C, $3D, $FF, $FF, $FF, $FD, $FF, $FF,
- $FF, $0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $A, $B, $C, $D, $E,
- $F, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $FF, $FF, $FF, $FF, $FF,
- $FF, $1A, $1B, $1C, $1D, $1E, $1F, $20, $21, $22, $23, $24, $25, $26, $27, $28,
- $29, $2A, $2B, $2C, $2D, $2E, $2F, $30, $31, $32, $33, $FF, $FF, $FF, $FF, $FF,
- $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
- $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
- $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
- $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
- $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
- $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
- $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
- $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
- );
- function B64InitializeDecoding(var Ctx : TSBBase64Context) : boolean;
- begin
-
- Ctx.TailBytes := 0;
- Ctx.EQUCount := 0;
-
- Result := true;
- end;
- function B64InitializeEncoding(var Ctx : TSBBase64Context; LineSize : integer;
- fEOL : TSBEOLMarker) : boolean;
- begin
-
- Result := false;
- Ctx.TailBytes := 0;
- Ctx.LineSize := LineSize;
- Ctx.LineWritten := 0;
- Ctx.EQUCount := 0;
- if LineSize < 4 then Exit;
- case fEOL of
- emCRLF :
- begin
- Move(CRLFByteArray[1], Ctx.fEOL[0], Length(CRLFByteArray));
- Ctx.EOLSize := Length(CRLFByteArray);
- end;
- emCR :
- begin
- Move(CRByteArray[1], Ctx.fEOL[0], Length(CRByteArray));
- Ctx.EOLSize := Length(CRByteArray);
- end;
- emLF :
- begin
- Move(LFByteArray[1], Ctx.fEOL[0], Length(LFByteArray));
- Ctx.EOLSize := Length(LFByteArray);
- end;
- else
- Ctx.EOLSize := 0;
- end;
- Result := true;
- end;
- function B64Encode(var Ctx : TSBBase64Context; Buffer : pointer; Size : integer;
- OutBuffer : pointer; var OutSize : integer) : boolean;
- var
- EstSize, I, Chunks : integer;
- begin
- EstSize := ((Size + Ctx.TailBytes) div 3) * 4;
- if (Ctx.LineSize > 0) and (Ctx.EOLSize > 0) then
- EstSize := EstSize + ((EstSize + Ctx.LineWritten) div Ctx.LineSize) * Ctx.EOLSize;
- if OutSize < EstSize then
- begin
- OutSize := EstSize;
- Result := false;
- Exit;
- end;
- OutSize := EstSize;
- if Size + Ctx.TailBytes < 3 then
- begin
- for I := 0 to Size - 1 do
- Ctx.Tail[Ctx.TailBytes + I] := PByteArray(Buffer)^[I];
- Inc(Ctx.TailBytes, Size);
- Result := true;
- OutSize := 0;
- Exit;
- end;
- if Ctx.TailBytes > 0 then
- begin
- for I := 0 to 2 - Ctx.TailBytes do
- Ctx.Tail[Ctx.TailBytes + I] := PByteArray(Buffer)^[I];
- Inc(Cardinal(Buffer), 3 - Ctx.TailBytes);
- Dec(Size, 3 - Ctx.TailBytes);
- Ctx.TailBytes := 0;
- Ctx.OutBuf[0] := Base64Symbols[Ctx.Tail[0] shr 2];
- Ctx.OutBuf[1] := Base64Symbols[((Ctx.Tail[0] and 3) shl 4) or (Ctx.Tail[1] shr 4)];
- Ctx.OutBuf[2] := Base64Symbols[((Ctx.Tail[1] and $f) shl 2) or (Ctx.Tail[2] shr 6)];
- Ctx.OutBuf[3] := Base64Symbols[Ctx.Tail[2] and $3f];
- if (Ctx.LineSize = 0) or (Ctx.LineWritten + 4 < Ctx.LineSize) then
- begin
- Move(Ctx.OutBuf[0], OutBuffer^, 4);
- Inc(Cardinal(OutBuffer), 4);
- Inc(Ctx.LineWritten, 4);
- end
- else
- begin
- I := Ctx.LineSize - Ctx.LineWritten;
- Move(Ctx.OutBuf[0], OutBuffer^, I);
- Inc(Cardinal(OutBuffer), I);
- Move(Ctx.fEOL[0], OutBuffer^, Ctx.EOLSize);
- Inc(Cardinal(OutBuffer), Ctx.EOLSize);
- Move(Ctx.OutBuf[I], OutBuffer^, 4 - I);
- Inc(Cardinal(OutBuffer), 4 - I);
- Ctx.LineWritten := 4 - I;
- end;
- end;
- while Size >= 3 do
- begin
- if Ctx.LineSize > 0 then
- begin
- Chunks := (Ctx.LineSize - Ctx.LineWritten) div 4;
- if Chunks > Size div 3 then
- Chunks := Size div 3;
- end
- else
- Chunks := Size div 3;
- for I := 0 to Chunks - 1 do
- begin
- PByte(OutBuffer)^ := Base64Symbols[PByteArray(Buffer)^[0] shr 2];
- Inc(Cardinal(OutBuffer));
- PByte(OutBuffer)^ := Base64Symbols[((PByteArray(Buffer)^[0] and 3) shl 4)
- or (PByteArray(Buffer)^[1] shr 4)];
- Inc(Cardinal(OutBuffer));
- PByte(OutBuffer)^ := Base64Symbols[((PByteArray(Buffer)^[1] and $f) shl 2)
- or (PByteArray(Buffer)^[2] shr 6)];
- Inc(Cardinal(OutBuffer));
- PByte(OutBuffer)^ := Base64Symbols[PByteArray(Buffer)^[2] and $3f];
- Inc(Cardinal(OutBuffer));
- Inc(Cardinal(Buffer), 3);
- end;
- Dec(Size, 3 * Chunks);
- if Ctx.LineSize > 0 then
- begin
- Inc(Ctx.LineWritten, Chunks * 4);
- if (Size >= 3) and (Ctx.LineSize - Ctx.LineWritten > 0) then
- begin
- Ctx.OutBuf[0] := Base64Symbols[PByteArray(Buffer)^[0] shr 2];
- Ctx.OutBuf[1] := Base64Symbols[((PByteArray(Buffer)^[0] and 3) shl 4)
- or (PByteArray(Buffer)^[1] shr 4)];
- Ctx.OutBuf[2] := Base64Symbols[((PByteArray(Buffer)^[1] and $f) shl 2)
- or (PByteArray(Buffer)^[2] shr 6)];
- Ctx.OutBuf[3] := Base64Symbols[PByteArray(Buffer)^[2] and $3f];
- Inc(Cardinal(Buffer), 3);
- Dec(Size, 3);
- I := Ctx.LineSize - Ctx.LineWritten;
- Move(Ctx.OutBuf[0], OutBuffer^, I);
- Inc(Cardinal(OutBuffer), I);
- if Ctx.EOLSize > 0 then
- Move(Ctx.fEOL[0], OutBuffer^, Ctx.EOLSize);
- Inc(Cardinal(OutBuffer), Ctx.EOLSize);
- Move(Ctx.OutBuf[I], OutBuffer^, 4 - I);
- Inc(Cardinal(OutBuffer), 4 - I);
- Ctx.LineWritten := 4 - I;
- end
- else if Ctx.LineWritten = Ctx.LineSize then
- begin
- Ctx.LineWritten := 0;
- if Ctx.EOLSize > 0 then
- begin
- Move(Ctx.fEOL[0], OutBuffer^, Ctx.EOLSize);
- Inc(Cardinal(OutBuffer), Ctx.EOLSize);
- end;
- end;
- end;
- end;
- if Size > 0 then
- begin
- Move(Buffer^, Ctx.Tail[0], Size);
- Ctx.TailBytes := Size;
- end;
- Result := true;
- end;
- function B64Decode(var Ctx : TSBBase64Context; Buffer : pointer; Size : integer;
- OutBuffer : pointer; var OutSize : integer) : boolean;
- var
- I, EstSize, EQUCount : integer;
- BufPtr : pointer;
- C : byte;
- begin
- if Size = 0 then
- begin
- Result := true;
- OutSize := 0;
- Exit;
- end;
- EQUCount := Ctx.EQUCount;
- EstSize := Ctx.TailBytes;
- BufPtr := Buffer;
- for I := 0 to Size - 1 do
- begin
- C := Base64Values[PByte(BufPtr)^];
- if C < 64 then Inc(EstSize)
- else if C = $ff then
- begin
- Result := false;
- OutSize := 0;
- Exit;
- end
- else if C = $fd then
- begin
- if EQUCount > 1 then
- begin
- Result := false;
- OutSize := 0;
- Exit;
- end;
- Inc(EQUCount);
- end;
- Inc(Cardinal(BufPtr));
- end;
- EstSize := (EstSize div 4) * 3;
- if OutSize < EstSize then
- begin
- OutSize := EstSize;
- Result := false;
- Exit;
- end;
- Ctx.EQUCount := EQUCount;
- OutSize := EstSize;
- while Size > 0 do
- begin
- C := Base64Values[PByte(Buffer)^];
- if C < 64 then
- begin
- Ctx.Tail[Ctx.TailBytes] := C;
- Inc(Ctx.TailBytes);
- if Ctx.TailBytes = 4 then
- begin
- PByte(OutBuffer)^ := (Ctx.Tail[0] shl 2) or (Ctx.Tail[1] shr 4);
- Inc(Cardinal(OutBuffer));
- PByte(OutBuffer)^ := ((Ctx.Tail[1] and $f) shl 4) or (Ctx.Tail[2] shr 2);
- Inc(Cardinal(OutBuffer));
- PByte(OutBuffer)^ := ((Ctx.Tail[2] and $3) shl 6) or Ctx.Tail[3];
- Inc(Cardinal(OutBuffer));
- Ctx.TailBytes := 0;
- end;
- end;
- Inc(Cardinal(Buffer));
- Dec(Size);
- end;
- Result := true;
- end;
- function B64FinalizeEncoding(var Ctx : TSBBase64Context;
- OutBuffer : pointer; var OutSize : integer) : boolean;
- begin
- if Ctx.TailBytes = 0 then
- begin
- { writing trailing EOL }
- if (Ctx.EOLSize > 0) and (Ctx.LineWritten > 0) then
- begin
- if OutSize < Ctx.EOLSize then
- begin
- OutSize := Ctx.EOLSize;
- Result := false;
- end
- else
- begin
- OutSize := Ctx.EOLSize;
- Result := true;
- Move(Ctx.fEOL[0], OutBuffer^, Ctx.EOLSize);
- end;
- end
- else
- begin
- OutSize := 0;
- Result := true;
- end;
- Exit;
- end;
- if OutSize < 4 + Ctx.EOLSize then
- begin
- OutSize := 4 + Ctx.EOLSize;
- Result := false;
- Exit;
- end;
- if Ctx.TailBytes = 1 then
- begin
- PByteArray(OutBuffer)^[0] := Base64Symbols[Ctx.Tail[0] shr 2];
- PByteArray(OutBuffer)^[1] := Base64Symbols[((Ctx.Tail[0] and 3) shl 4)];
- PByteArray(OutBuffer)^[2] := $3D; // '='
- PByteArray(OutBuffer)^[3] := $3D; // '='
- end
- else if Ctx.TailBytes = 2 then
- begin
- PByteArray(OutBuffer)^[0] := Base64Symbols[Ctx.Tail[0] shr 2];
- PByteArray(OutBuffer)^[1] := Base64Symbols[((Ctx.Tail[0] and 3) shl 4) or (Ctx.Tail[1] shr 4)];
- PByteArray(OutBuffer)^[2] := Base64Symbols[((Ctx.Tail[1] and $f) shl 2)];
- PByteArray(OutBuffer)^[3] := $3D; // '='
- end;
- if Ctx.EOLSize > 0 then
- Move(Ctx.fEOL[0], PByteArray(OutBuffer)^[4], Ctx.EOLSize);
-
- OutSize := 4 + Ctx.EOLSize;
- Result := true;
- end;
- function B64FinalizeDecoding(var Ctx : TSBBase64Context;
- OutBuffer : pointer; var OutSize : integer) : boolean;
- begin
- if (Ctx.EQUCount = 0) then
- begin
- OutSize := 0;
- Result := Ctx.TailBytes = 0;
- Exit;
- end
- else if (Ctx.EQUCount = 1) then
- begin
- if Ctx.TailBytes <> 3 then
- begin
- Result := false;
- OutSize := 0;
- Exit;
- end;
- if OutSize < 2 then
- begin
- OutSize := 2;
- Result := false;
- Exit;
- end;
- PByte(OutBuffer)^ := (Ctx.Tail[0] shl 2) or (Ctx.Tail[1] shr 4);
- Inc(Cardinal(OutBuffer));
- PByte(OutBuffer)^ := ((Ctx.Tail[1] and $f) shl 4) or (Ctx.Tail[2] shr 2);
- OutSize := 2;
- Result := true;
- end
- else if (Ctx.EQUCount = 2) then
- begin
- if Ctx.TailBytes <> 2 then
- begin
- Result := false;
- OutSize := 0;
- Exit;
- end;
- if OutSize < 1 then
- begin
- OutSize := 1;
- Result := false;
- Exit;
- end;
- PByte(OutBuffer)^ := (Ctx.Tail[0] shl 2) or (Ctx.Tail[1] shr 4);
- OutSize := 1;
- Result := true;
- end
- else
- begin
- Result := false;
- OutSize := 0;
- end;
- end;
- end.