SBPEM.pas
上传用户:qdyddl
上传日期:2014-04-21
资源大小:11640k
文件大小:31k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. (******************************************************)
  2. (*                                                    *)
  3. (*            EldoS SecureBlackbox Library            *)
  4. (*                                                    *)
  5. (*      Copyright (c) 2002-2007 EldoS Corporation     *)
  6. (*           http://www.secureblackbox.com            *)
  7. (*                                                    *)
  8. (******************************************************)
  9. {$I SecBbox.inc}
  10. unit SBPEM;
  11. interface
  12. uses
  13.   SysUtils,
  14.   Classes,
  15.   {$ifndef CLX_USED}
  16.   Windows,
  17.   {$else}
  18.   Libc,
  19.   {$endif}
  20.   SBUtils;
  21. const
  22.   PEM_DECODE_RESULT_OK                  = Integer(0);
  23.   PEM_DECODE_RESULT_INVALID_FORMAT      = Integer($1D01);
  24.   PEM_DECODE_RESULT_INVALID_PASSPHRASE  = Integer($1D02);
  25.   PEM_DECODE_RESULT_NOT_ENOUGH_SPACE    = Integer($1D03);
  26.   PEM_DECODE_RESULT_UNKNOWN_CIPHER      = Integer($1D04);
  27. type
  28.   TSBBase64Context = record
  29.     Tail : array [0..3] of byte;
  30.     TailBytes : integer;
  31.     LineWritten : integer;
  32.     LineSize : integer;
  33.     fEOL : array [0..3] of byte;
  34.     EOLSize : integer;
  35.     OutBuf : array [0..3] of byte;
  36.     EQUCount : integer;
  37.   end;
  38.   TElPEMProcessor = class(TSBComponentBase)
  39.   protected
  40.     FHeader : string;
  41.     FPassphrase: string;
  42.   public
  43.     function PEMEncode(const InBuffer : ByteArray; var OutBuffer : ByteArray; Encrypt : boolean) : boolean; overload;
  44.     function PEMDecode(const InBuffer : ByteArray; var OutBuffer : ByteArray) : integer;  overload;
  45.     function PEMEncode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
  46.       var OutSize : integer; Encrypt : boolean) : boolean; overload;
  47.     function PEMDecode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
  48.       var OutSize : integer) : integer; overload;
  49.   published
  50.     property Header : string read FHeader write FHeader;
  51.     property Passphrase: string read FPassphrase write FPassphrase;
  52.   end;
  53. function Encode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
  54.   var OutSize : integer; const Header : string; Encrypt : boolean;
  55.   const PassPhrase : string) : boolean;
  56. function Decode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
  57.   const PassPhrase : string; var OutSize : integer; var Header : string) : integer;
  58. function IsBase64UnicodeSequence(Buffer : pointer; Size : integer) : boolean;
  59. function IsBase64Sequence(Buffer : pointer; Size : integer) : boolean;
  60. function B64InitializeEncoding(var Ctx : TSBBase64Context; LineSize : integer;
  61.   fEOL : TSBEOLMarker) : boolean;  
  62. function B64InitializeDecoding(var Ctx : TSBBase64Context) : boolean;  
  63. function B64Encode(var Ctx : TSBBase64Context; Buffer : pointer; Size : integer;
  64.   OutBuffer : pointer; var OutSize : integer) : boolean;
  65. function B64Decode(var Ctx : TSBBase64Context; Buffer : pointer; Size : integer;
  66.   OutBuffer: pointer; var OutSize : integer) : boolean;
  67. function B64FinalizeEncoding(var Ctx : TSBBase64Context;
  68.   OutBuffer : pointer; var OutSize : integer) : boolean;
  69. function B64FinalizeDecoding(var Ctx : TSBBase64Context;
  70.   OutBuffer : pointer; var OutSize : integer) : boolean;
  71. type
  72.   EPEMError =  class(ESecureBlackboxError);
  73. procedure RaisePEMError(ErrorCode : integer); 
  74. implementation
  75. uses
  76.   {$ifndef SBB_NO_DES}
  77.   SBDES,
  78.   SB3DES,
  79.   {$endif}
  80.   SBConstants,
  81.   SBMath,
  82.   SBMD
  83.   ;
  84. resourcestring
  85.   sInvalidPEMFormat     = 'Invalid file format (possibly not a PEM?)';
  86.   sIncorrectPassphrase  = 'Incorrect password';
  87.   sNotEnoughBufferSpace = 'Not enough buffer space';
  88.   sUnknownCipher        = 'Unsupported data encryption method';
  89. procedure RaisePEMError(ErrorCode : integer);
  90. begin
  91.   case ErrorCode of
  92.     PEM_DECODE_RESULT_INVALID_FORMAT     : raise EPEMError.Create(sInvalidPEMFormat, ErrorCode{$ifndef HAS_DEF_PARAMS}{$ifndef FPC}, 0{$endif}{$endif});
  93.     PEM_DECODE_RESULT_INVALID_PASSPHRASE : raise EPEMError.Create(sIncorrectPassphrase, ErrorCode{$ifndef HAS_DEF_PARAMS}{$ifndef FPC}, 0{$endif}{$endif});
  94.     PEM_DECODE_RESULT_NOT_ENOUGH_SPACE   : raise EPEMError.Create(sNotEnoughBufferSpace, ErrorCode{$ifndef HAS_DEF_PARAMS}{$ifndef FPC}, 0{$endif}{$endif});
  95.     PEM_DECODE_RESULT_UNKNOWN_CIPHER     : raise EPEMError.Create(sUnknownCipher, ErrorCode{$ifndef HAS_DEF_PARAMS}{$ifndef FPC}, 0{$endif}{$endif});
  96.     else
  97.       exit;
  98.   end;
  99. end;
  100. (*
  101. {$ifndef SBB_NO_DES}
  102. procedure ConvertPassPhraseToKey(const PassPhrase : string; var Key : TDESKey;
  103.   var IV : TDESBuffer);
  104. var
  105.   MD1, MD2, MD3 : TMessageDigest128;
  106.   {$ifdef DELPHI_NET}
  107.   TmpBuf : ByteArray;
  108.   TmpStr : AnsiString;
  109.   CnvPwd : ByteArray;
  110.   {$endif}
  111. begin
  112.   {$ifdef DELPHI_NET}
  113.   CnvPwd := Encoding.ASCII.GetBytes(PassPhrase);
  114. //  TmpStr := CloneBuffer(CnvPwd);
  115. //  SetLength(TmpBuf, Length(TmpStr));
  116. //  if Length(TmpBuf) > 0 then
  117. //    Move(TmpStr, 0, TmpBuf, 0, Length(TmpBuf));
  118. //  MD1 := HashMD5(TmpBuf, Length(TmpBuf));
  119.   MD1 := HashMD5(CnvPwd, Length(CnvPwd));
  120.   {$ifndef CHROME}
  121.   TmpStr := PassPhrase + base64Pad + PassPhrase;
  122.   {$else}
  123.   TmpStr := SBConcatBuffers(CnvPwd, base64PadByteArray);
  124.   TmpStr := SBConcatBuffers(TmpStr, CnvPwd);
  125.   {$endif}
  126.   {$ifndef CHROME}
  127.   SetLength(TmpBuf, Length(TmpStr));
  128.   if Length(TmpBuf) > 0 then
  129.     Move(TmpStr, 0, TmpBuf, 0, Length(TmpBuf));
  130.   {$else}
  131.   TmpBuf := TmpStr;
  132.   {$endif}
  133.   MD2 := HashMD5(TmpBuf, Length(TmpBuf));
  134.   {$else}
  135.   MD1 := HashMD5(PassPhrase);
  136.   MD2 := HashMD5(PassPhrase + base64Pad + PassPhrase);
  137.   {$endif}
  138.   MD3.A := MD1.A xor MD2.A;
  139.   MD3.B := MD1.B xor MD2.B;
  140.   MD3.C := MD1.C xor MD2.C;
  141.   MD3.D := MD1.D xor MD2.D;
  142.   {$ifdef DELPHI_NET}
  143.   TmpBuf := StructureToByteArray(MD3);
  144.   Move(TmpBuf, 0, Key, 0, 8);
  145.   Move(TmpBuf, 8, IV, 0, 8);
  146.   {$else}
  147.   Move(PByteArray(@MD3)[0], Key[0], 8);
  148.   Move(PByteArray(@MD3)[8], IV[0], 8);
  149.   {$endif}
  150. end;
  151. {$endif}
  152. *)
  153. function BytesToKey(const Passphrase : BufferType; const Salt : BufferType; Needed: integer) : BufferType;
  154. var
  155.   Context : TMD5Context;
  156.   AM : integer;
  157.   MDS, I, KeyCount : integer;
  158.   M128 : TMessageDigest128;
  159.   KeyPtr : ^byte;
  160. begin
  161.   AM := 0;
  162.   MDS := 0;
  163.   SetLength(Result, Needed);
  164.   KeyPtr := @Result[1];
  165.   KeyCount := Needed;
  166.   while true do
  167.   begin
  168.     SBMD.InitializeMD5(Context);
  169.     Inc(AM);
  170.     if (AM <> 0) then
  171.       SBMD.HashMD5(Context, @M128, MDS);
  172.     SBMD.HashMD5(Context, @Passphrase[1], Length(Passphrase));
  173.     if Length(Salt) <> 0 then
  174.       SBMD.HashMD5(Context, @Salt[1], Length(Salt));
  175.     M128 := SBMD.FinalizeMD5(Context);
  176.     I := 0;
  177.     MDS := 16;
  178.     while true do
  179.     begin
  180.       if KeyCount = 0 then
  181.         Break;
  182.       if I = MDS then
  183.         Break;
  184.       KeyPtr^ := PByteArray(@M128)[I];
  185.       Inc(KeyPtr);
  186.       Dec(KeyCount);
  187.       Inc(I);
  188.     end;
  189.     if KeyCount = 0 then
  190.       Break;
  191.   end;
  192. end;
  193. function Encode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
  194.   var OutSize : integer; const Header : string; Encrypt : boolean;
  195.   const PassPhrase : string) : boolean;
  196. var
  197.   InBuf,
  198.   Buf : ByteArray;
  199.   Sz, I, EstSize : integer;
  200.   OutSz : cardinal;
  201.   PEMBeginLine, PEMEndLine, PEMHeaders : AnsiString;
  202.   {$ifndef SBB_NO_DES}
  203.   DESKey : T3DESKey;
  204.   DESIV : T3DESBuffer;
  205.   Ctx : T3DESContext;
  206.   {$endif}
  207.   Key, Salt : BufferType;
  208.   //RandCtx : TRC4RandomContext;
  209. begin
  210.   Result := true;
  211.   {$ifndef SBB_NO_DES}
  212.   if Encrypt then
  213.   begin
  214.     SetLength(Salt, 8);
  215.     //LRC4Init(RandCtx);
  216.     for I := 1 to 8 do
  217.       Salt[I] := Chr(SBRndGenerate(256){LRC4RandomByte(RandCtx)});
  218.     Key := BytesToKey(Passphrase, Salt, 24);
  219.     Move(Key[1], DESKey[0], 24);
  220.     Move(Salt[1], DESIV[0], 8);
  221.     PEMHeaders := 'Proc-Type: 4,ENCRYPTED'#$0A;
  222.     PEMHeaders := PEMHeaders + 'DEK-Info: DES-EDE3-CBC,';
  223.     for I := 0 to 7 do
  224.       PEMHeaders := PEMHeaders + IntToHex(DESIV[I], 2);
  225.     PEMHeaders := PEMHeaders + #$0A#$0A;
  226.     SetLength(InBuf, (InSize div 8 + 1) * 8);
  227.     Move(InBuffer^, InBuf[0], InSize);
  228.     FillChar(InBuf[InSize], Length(InBuf) - InSize, Chr(Length(InBuf) - InSize));
  229.     SB3DES.InitializeEncryptionCBC(Ctx, DESKey, DESIV);
  230.     OutSz := Length(InBuf);
  231.     SB3DES.EncryptCBC(Ctx, @InBuf[0], Length(InBuf), @InBuf[0], OutSz);
  232.     SetLength(Buf, Length(InBuf) * 2);
  233.     Sz := Length(InBuf) * 2;
  234.     if not Base64Encode(@InBuf[0], Length(InBuf), @Buf[0], Sz) then
  235.     begin
  236.       Result := false;
  237.       Exit;
  238.     end;
  239.   end
  240.   else
  241.   {$endif}
  242.   begin
  243.     SetLength(Buf, InSize * 2);
  244.     Sz := InSize * 2;
  245.     if not Base64Encode(InBuffer, InSize, @Buf[0], Sz) then
  246.     begin
  247.       Result := false;
  248.       Exit;
  249.     end;
  250.     PEMHeaders := '';
  251.   end;
  252.   
  253.   PEMBeginLine := BeginLine + Header + Line + #$0A + PEMHeaders;
  254.   PEMEndLine := EndLine + Header + Line + #$0A;
  255.   { Checking whether we have enough space in buffer }
  256.   EstSize := Length(PEMBeginLine) + Length(PEMEndLine) + Sz;
  257.   if (OutSize < EstSize)  then
  258.   begin
  259.     OutSize := EstSize;
  260.     Result := false;
  261.     Exit;
  262.   end;
  263.   Move(PEMBeginLine[1], PByteArray(OutBuffer)[0], Length(PEMBeginLine));
  264.   SetLength(Buf, Sz);
  265.   Move(Buf[0], PByteArray(OutBuffer)[Length(PEMBeginLine)], Length(Buf));
  266.   Move(PEMEndLine[1], PByteArray(OutBuffer)[Length(PEMBeginLine) + Length(Buf)],
  267.     Length(PEMEndLine));
  268.   OutSize := EstSize; //Length(PEMBeginLine) + Length(Buf) + Length(PEMEndLine);
  269.   SetLength(Buf, 0);
  270. end;
  271. function HexStringToBuffer(const HexStr : string) : BufferType;
  272.   function HexBytesToSym(B1, B2 : char) : byte;
  273.   var
  274.     P1, P2 : byte;
  275.   begin
  276.     if (B1 >= 'A') and (B1 <= 'F') then
  277.       P1 := Ord(B1) - Ord('A') + 10
  278.     else if (B1 >= '0') and (B1 <= '9') then
  279.       P1 := Ord(B1) - Ord('0')
  280.     else
  281.       P1 := 0;
  282.     if (B2 >= 'A') and (B2 <= 'F') then
  283.       P2 := Ord(B2) - Ord('A') + 10
  284.     else if (B2 >= '0') and (B2 <= '9') then
  285.       P2 := Ord(B2) - Ord('0')
  286.     else
  287.       P2 := 0;
  288.     Result := (P1 shl 4) or P2;
  289.   end;
  290. var
  291.   I : integer;
  292. begin
  293.   if Length(HexStr) mod 2 <> 0 then
  294.     SetLength(Result, 0)
  295.   else
  296.   begin
  297.     I := 1;
  298.     SetLength(Result, Length(HexStr) div 2);
  299.     while I <= Length(Result) do
  300.     begin
  301.       Result[I] := Chr(HexBytesToSym(HexStr[I * 2 - 1], HexStr[I * 2]));
  302.       Inc(I);
  303.     end;
  304.   end;
  305. end;
  306. function Decode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
  307.   const PassPhrase : string; var OutSize : integer; var Header : string) : integer;
  308. var
  309.   S1, S2 : BufferType;
  310.   S, Headers, Tmp : String;
  311.   I, HeaderEnd, Res, Cipher, I1, I2, I3 : integer;
  312.   {$ifndef SBB_NO_DES}
  313.   DESIV : TDESBuffer;
  314.   DESEDE3IV : T3DESBuffer;
  315.   DESKey : TDESKey;
  316.   DESEDE3Key : T3DESKey;
  317.   Ctx : TDESContext;
  318.   CtxEDE : T3DESContext;
  319.   {$endif}
  320.   Sz : cardinal;
  321.   EolLen : integer;
  322. begin
  323.   Result := PEM_DECODE_RESULT_OK;
  324.   SetLength(S, InSize);
  325.   Move(InBuffer^, S[1], InSize);
  326.   if Pos(BeginLine, S) <= 0 then
  327.   begin
  328.     Result := PEM_DECODE_RESULT_INVALID_FORMAT;
  329.     Exit;
  330.   end;
  331.   I1 := Pos(#13#13#10, S);
  332.   I2 := Pos(#13#10, S);
  333.   I3 := Pos(#10, S);
  334.   if I1 = 0 then I1 := $7FFFFFFF;
  335.   if I2 = 0 then I2 := $7FFFFFFF;
  336.   if I3 = 0 then I3 := $7FFFFFFF;
  337.   I := Min(Min(I1, I2), I3);
  338.   if I = I1 then
  339.     EolLen := 3
  340.   else if I = I2 then
  341.     EolLen := 2
  342.   else
  343.     EolLen := 1;
  344.   if I = $7FFFFFFF then
  345.   begin
  346.     Result := PEM_DECODE_RESULT_INVALID_FORMAT;
  347.     OutSize := 0;
  348.     Exit;
  349.   end;
  350.   Header := Copy(S, Length(BeginLine) + 1, I - Length(Line) - Length(BeginLine) - 1);
  351.   S := Copy(S, I + EolLen, Length(S));
  352.   if Pos('Proc-Type', S) = 1 then
  353.   begin
  354.     HeaderEnd := Pos(#$0D#$0D#$0A#$0D#$0D#$0A, S);
  355.     if HeaderEnd = 0 then
  356.     begin
  357.       HeaderEnd := Pos(#$0A#$0A, S);
  358.       if HeaderEnd = 0 then
  359.         HeaderEnd := Pos(#$0D#$0A#$0D#$0A, S);
  360.     end;
  361.     Headers := Copy(S, 1, HeaderEnd - 1);
  362.     
  363.     while Pos('DEK-Info:', Headers) > 1 do
  364.     begin
  365.       I := Pos(#$0A, Headers);
  366.       Headers := Copy(Headers, I + 1, Length(Headers));
  367.     end;
  368.     if Pos('DEK-Info:', Headers) = 1 then
  369.     begin
  370.       I := Pos(#$0A, Headers);
  371.       if I > 0 then
  372.         Headers := Copy(Headers, 1, I - 1);
  373.       I := Pos(' ', Headers);
  374.       Headers := Copy(Headers, I + 1, Length(Headers));
  375.       I := Pos(',', Headers);
  376.       Tmp := Copy(Headers, 1, I - 1);
  377.       {$ifndef SBB_NO_DES}
  378.       if CompareStr('DES-CBC', Tmp) = integer(0) then
  379.         Cipher := SB_ALGORITHM_CNT_DES
  380.       else
  381.       if CompareStr('DES-EDE3-CBC', Tmp) = integer(0) then
  382.         Cipher := SB_ALGORITHM_CNT_3DES
  383.       else
  384.       {$endif}
  385.       begin
  386.         Result := PEM_DECODE_RESULT_UNKNOWN_CIPHER;
  387.         Exit;
  388.       end;
  389.       
  390.       Tmp := Copy(Headers, I + 1, Length(Headers));
  391.       S1 := HexStringToBuffer(Tmp);
  392.       {$ifndef SBB_NO_DES}
  393.       if Cipher = SB_ALGORITHM_CNT_DES then
  394.       begin
  395.         S2 := BytesToKey(Passphrase, S1, 8);
  396.         Move(S2[1], DESKey[0], 8);
  397.         Move(S1[1], DESIV[0], 8);
  398.       end
  399.       else
  400.       if Cipher = SB_ALGORITHM_CNT_3DES then
  401.       begin
  402.         S2 := BytesToKey(Passphrase, S1, 24);
  403.         Move(S2[1], DESEDE3Key[0], 24);
  404.         Move(S1[1], DESEDE3IV[0], 8);
  405.       end;
  406.       {$endif}
  407.       Headers := '';
  408.       {$ifndef SBB_NO_DES}
  409.       for I := 0 to 7 do
  410.         if Cipher = SB_ALGORITHM_CNT_DES then
  411.           Headers := Headers + IntToHex(DESIV[I], 2)
  412.         else
  413.         if Cipher = SB_ALGORITHM_CNT_3DES then
  414.           Headers := Headers + IntToHex(DESEDE3IV[I], 2);
  415.       {$endif}
  416.       if CompareStr(Headers, Tmp) <> integer(0) then
  417.       begin
  418.         Result := PEM_DECODE_RESULT_INVALID_PASSPHRASE;
  419.         Exit;
  420.       end;
  421.       I := Pos(EndLine, S);
  422.       Res := Base64Decode(@S[HeaderEnd + 2], I - HeaderEnd - 2, OutBuffer, OutSize);
  423.       if Res = 0 then
  424.       begin
  425.         {$ifndef SBB_NO_DES}
  426.         if Cipher = SB_ALGORITHM_CNT_DES then
  427.         begin
  428.           SBDES.InitializeDecryptionCBC(Ctx, DESKey, DESIV);
  429.           Sz := OutSize;
  430.           SBDES.DecryptCBC(Ctx, OutBuffer, OutSize, OutBuffer, Sz);
  431.         end
  432.         else
  433.         if Cipher = SB_ALGORITHM_CNT_3DES then
  434.         begin
  435.           SB3DES.InitializeDecryptionCBC(CtxEDE, DESEDE3Key, DESEDE3IV);
  436.           Sz := OutSize;
  437.           SB3DES.DecryptCBC(CtxEDE, OutBuffer, OutSize, OutBuffer, Sz);
  438.         end;
  439.         {$endif}
  440.         if PByteArray(OutBuffer)[Sz - 1] > 8 then
  441.         begin
  442.           Result := PEM_DECODE_RESULT_INVALID_PASSPHRASE;
  443.           Exit;
  444.         end;
  445.         OutSize := Sz - PByteArray(OutBuffer)[Sz - 1];
  446.         if OutSize < 0 then
  447.         begin
  448.           Result := PEM_DECODE_RESULT_INVALID_PASSPHRASE;
  449.           Exit;
  450.         end;
  451.         Result := PEM_DECODE_RESULT_OK;
  452.       end
  453.       else
  454.       if Res = BASE64_DECODE_NOT_ENOUGH_SPACE then
  455.       begin
  456.         Result := PEM_DECODE_RESULT_NOT_ENOUGH_SPACE;
  457.         Exit;
  458.       end
  459.       else
  460.       if Res = BASE64_DECODE_INVALID_CHARACTER then
  461.       begin
  462.         Result := PEM_DECODE_RESULT_INVALID_FORMAT;
  463.         Exit;
  464.       end;
  465.     end
  466.     else
  467.     begin
  468.       Result := PEM_DECODE_RESULT_INVALID_FORMAT;
  469.       Exit;
  470.     end;
  471.   end
  472.   else
  473.   begin
  474.     I := Pos(EndLine, S);
  475.     Result := Base64Decode(@S[1], I - 1, OutBuffer, OutSize);
  476.     case Result of
  477.       BASE64_DECODE_OK:
  478.         Result := PEM_DECODE_RESULT_OK;
  479.       BASE64_DECODE_NOT_ENOUGH_SPACE:
  480.         Result := PEM_DECODE_RESULT_NOT_ENOUGH_SPACE
  481.     else
  482.       Result := PEM_DECODE_RESULT_INVALID_FORMAT;
  483.     end;
  484.   end;
  485. end;
  486. function TElPEMProcessor.PEMEncode(const InBuffer : ByteArray; var OutBuffer : ByteArray; Encrypt : boolean) : boolean;
  487. var OutSize : integer;
  488. begin
  489.   OutSize := 0;
  490.   Encode(InBuffer, Length(InBuffer), nil, OutSize, FHeader, Encrypt, FPassphrase);
  491.   SetLength(OutBuffer, OutSize);
  492.   result := Encode(InBuffer, Length(InBuffer), OutBuffer, OutSize, FHeader, Encrypt, FPassphrase);
  493.   if result then
  494.   begin
  495.     if (Length(OutBuffer) <> OutSize) then
  496.      SetLength(OutBuffer, OutSize);
  497.   end
  498.   else
  499.     SetLength(OutBuffer, 0);
  500. end;
  501. function TElPEMProcessor.PEMEncode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
  502.   var OutSize : integer; Encrypt : boolean) : boolean;
  503. begin
  504.   result := Encode(InBuffer, InSize, OutBuffer, OutSize, FHeader, Encrypt, FPassphrase);
  505. end;
  506. function TElPEMProcessor.PEMDecode(const InBuffer : ByteArray; var OutBuffer : ByteArray) : integer;
  507. var OutSize : integer;
  508. begin
  509.   OutSize := 0;
  510.   result := Decode(InBuffer, Length(InBuffer),  nil, FPassphrase, OutSize, FHeader);
  511.   if result = PEM_DECODE_RESULT_NOT_ENOUGH_SPACE then
  512.   begin
  513.     SetLength(OutBuffer, OutSize);
  514.     result := Decode(InBuffer, Length(InBuffer),  OutBuffer, FPassphrase, OutSize, FHeader);
  515.     if result = 0 then
  516.     begin
  517.       if (Length(OutBuffer) <> OutSize) then
  518.        SetLength(OutBuffer, OutSize);
  519.     end
  520.     else
  521.       SetLength(OutBuffer, 0);
  522.   end
  523.   else
  524.     SetLength(OutBuffer, 0);
  525. end;
  526. function TElPEMProcessor.PEMDecode(InBuffer : pointer; InSize : integer; OutBuffer : pointer;
  527.   var OutSize : integer) : integer;
  528. begin
  529.   result := Decode(InBuffer, InSize, OutBuffer, FPassphrase, OutSize, FHeader);
  530. end;
  531. function IsBase64UnicodeSequence(Buffer : pointer; Size : integer) : boolean;
  532. var i : integer;
  533.     eqcnt : integer;
  534. begin
  535.   result := true;
  536.   i := 0;
  537.   eqcnt := 0;
  538.   while i < Size do
  539.   begin
  540.     if PByteArray(Buffer)[i + 1] <> 0 then
  541.     begin
  542.       result := false;
  543.       exit;
  544.     end;
  545.     case Char(PByteArray(Buffer)[i]) of
  546.       'A' .. 'Z',
  547.       'a' .. 'z',
  548.       '0' .. '9',
  549.       '+',   '/':
  550.         begin
  551.           if eqcnt = 0 then
  552.           begin
  553.             inc(i, 2);
  554.             continue;
  555.           end
  556.           else
  557.           begin
  558.             result := false;
  559.             break;
  560.           end;
  561.         end;
  562.       #0:
  563.         begin
  564.           if eqcnt > 0 then
  565.           begin
  566.             inc(i, 2);
  567.             continue;
  568.           end
  569.           else
  570.           begin
  571.             result := false;
  572.             break;
  573.           end;
  574.         end;
  575.       #13, #10:
  576.         begin
  577.           inc(i, 2);
  578.           continue;
  579.         end;
  580.       '=':
  581.         begin
  582.           if eqcnt < 2 then
  583.           begin
  584.             inc(eqcnt);
  585.             inc(i, 2);
  586.             Continue;
  587.           end
  588.           else
  589.           begin
  590.             result := false;
  591.             exit;
  592.           end;
  593.         end;
  594.       else
  595.       begin
  596.         result := false;
  597.         exit;
  598.       end;
  599.     end;
  600.   end;
  601. end;
  602. function IsBase64Sequence(Buffer : pointer; Size : integer) : boolean;
  603. var i : integer;
  604.     eqcnt : integer;
  605. begin
  606.   result := true;
  607.   eqcnt := 0;
  608.   for i := 0 to Size - 1 do
  609.   begin
  610.     case Char(PByteArray(Buffer)[i]) of
  611.       'A' .. 'Z',
  612.       'a' .. 'z',
  613.       '0' .. '9',
  614.       '+',   '/':
  615.         begin
  616.           if eqcnt = 0 then
  617.             continue
  618.           else
  619.           begin
  620.             result := false;
  621.             break;
  622.           end;
  623.         end;
  624.       #0:
  625.         begin
  626.           if eqcnt > 0 then
  627.           begin
  628.             continue;
  629.           end
  630.           else
  631.           begin
  632.             result := false;
  633.             break;
  634.           end;
  635.         end;
  636.       #13, #10:
  637.         begin
  638.           continue;
  639.         end;
  640.       '=':
  641.         begin
  642.           if eqcnt < 2 then
  643.           begin
  644.             inc(eqcnt);
  645.             Continue;
  646.           end
  647.           else
  648.           begin
  649.             result := false;
  650.             exit;
  651.           end;
  652.         end;
  653.       else
  654.       begin
  655.         result := false;
  656.         exit;
  657.       end;
  658.     end;
  659.   end;
  660. end;
  661. { Base64 processing routines }
  662. const
  663.   Base64Symbols : array [0..63] of byte =
  664.     (
  665.      $41, $42, $43, $44, $45, $46, $47, $48, $49, $4A, $4B, $4C, $4D, $4E, $4F, $50,
  666.      $51, $52, $53, $54, $55, $56, $57, $58, $59, $5A, $61, $62, $63, $64, $65, $66,
  667.      $67, $68, $69, $6A, $6B, $6C, $6D, $6E, $6F, $70, $71, $72, $73, $74, $75, $76,
  668.      $77, $78, $79, $7A, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $2B, $2F
  669.     );
  670.   Base64Values : array [0..255] of byte =
  671.     (
  672.      $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FE, $FE, $FF, $FF, $FE, $FF, $FF,
  673.      $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  674.      $FE, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $3E, $FF, $FF, $FF, $3F,
  675.      $34, $35, $36, $37, $38, $39, $3A, $3B, $3C, $3D, $FF, $FF, $FF, $FD, $FF, $FF,
  676.      $FF,  $0,  $1,  $2,  $3,  $4,  $5,  $6,  $7,  $8,  $9,  $A,  $B,  $C,  $D,  $E,
  677.       $F, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $FF, $FF, $FF, $FF, $FF,
  678.      $FF, $1A, $1B, $1C, $1D, $1E, $1F, $20, $21, $22, $23, $24, $25, $26, $27, $28,
  679.      $29, $2A, $2B, $2C, $2D, $2E, $2F, $30, $31, $32, $33, $FF, $FF, $FF, $FF, $FF,
  680.      $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  681.      $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  682.      $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  683.      $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  684.      $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  685.      $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  686.      $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF,
  687.      $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF
  688.     );
  689. function B64InitializeDecoding(var Ctx : TSBBase64Context) : boolean;
  690. begin
  691.   
  692.   Ctx.TailBytes := 0;
  693.   Ctx.EQUCount := 0;  
  694.  
  695.   Result := true;
  696. end;
  697. function B64InitializeEncoding(var Ctx : TSBBase64Context; LineSize : integer;
  698.   fEOL : TSBEOLMarker) : boolean;
  699. begin
  700.   
  701.   Result := false;
  702.   Ctx.TailBytes := 0;
  703.   Ctx.LineSize := LineSize;
  704.   Ctx.LineWritten := 0;
  705.   Ctx.EQUCount := 0;
  706.   if LineSize < 4 then Exit;
  707.   case fEOL of
  708.   emCRLF :
  709.     begin
  710.       Move(CRLFByteArray[1], Ctx.fEOL[0], Length(CRLFByteArray));
  711.       Ctx.EOLSize := Length(CRLFByteArray);
  712.     end;
  713.   emCR :
  714.     begin
  715.       Move(CRByteArray[1], Ctx.fEOL[0], Length(CRByteArray));
  716.       Ctx.EOLSize := Length(CRByteArray);
  717.     end;
  718.   emLF :
  719.     begin
  720.       Move(LFByteArray[1], Ctx.fEOL[0], Length(LFByteArray));
  721.       Ctx.EOLSize := Length(LFByteArray);
  722.     end;
  723.     else
  724.       Ctx.EOLSize := 0;
  725.   end;
  726.   Result := true;
  727. end;
  728. function B64Encode(var Ctx : TSBBase64Context; Buffer : pointer; Size : integer;
  729.   OutBuffer : pointer; var OutSize : integer) : boolean;
  730. var
  731.   EstSize, I, Chunks : integer;
  732. begin
  733.   EstSize := ((Size + Ctx.TailBytes) div 3) * 4;
  734.   if (Ctx.LineSize > 0) and (Ctx.EOLSize > 0) then
  735.     EstSize := EstSize + ((EstSize + Ctx.LineWritten) div Ctx.LineSize) * Ctx.EOLSize;
  736.   if OutSize < EstSize then
  737.   begin
  738.     OutSize := EstSize;
  739.     Result := false;
  740.     Exit;
  741.   end;
  742.   OutSize := EstSize;
  743.   if Size + Ctx.TailBytes < 3 then
  744.   begin
  745.     for I := 0 to Size - 1 do
  746.       Ctx.Tail[Ctx.TailBytes + I] := PByteArray(Buffer)^[I];
  747.     Inc(Ctx.TailBytes, Size);
  748.     Result := true;
  749.     OutSize := 0;
  750.     Exit;
  751.   end;
  752.   if Ctx.TailBytes > 0 then
  753.   begin
  754.     for I := 0 to 2 - Ctx.TailBytes do
  755.       Ctx.Tail[Ctx.TailBytes + I] := PByteArray(Buffer)^[I];
  756.     Inc(Cardinal(Buffer), 3 - Ctx.TailBytes);
  757.     Dec(Size, 3 - Ctx.TailBytes);
  758.     Ctx.TailBytes := 0;
  759.     Ctx.OutBuf[0] := Base64Symbols[Ctx.Tail[0] shr 2];
  760.     Ctx.OutBuf[1] := Base64Symbols[((Ctx.Tail[0] and 3) shl 4) or (Ctx.Tail[1] shr 4)];
  761.     Ctx.OutBuf[2] := Base64Symbols[((Ctx.Tail[1] and $f) shl 2) or (Ctx.Tail[2] shr 6)];
  762.     Ctx.OutBuf[3] := Base64Symbols[Ctx.Tail[2] and $3f];
  763.     if (Ctx.LineSize = 0) or (Ctx.LineWritten + 4 < Ctx.LineSize) then
  764.     begin
  765.       Move(Ctx.OutBuf[0], OutBuffer^, 4);
  766.       Inc(Cardinal(OutBuffer), 4);
  767.       Inc(Ctx.LineWritten, 4);
  768.     end
  769.     else
  770.     begin
  771.       I := Ctx.LineSize - Ctx.LineWritten;
  772.       Move(Ctx.OutBuf[0], OutBuffer^, I);
  773.       Inc(Cardinal(OutBuffer), I);
  774.       Move(Ctx.fEOL[0], OutBuffer^, Ctx.EOLSize);
  775.       Inc(Cardinal(OutBuffer), Ctx.EOLSize);
  776.       Move(Ctx.OutBuf[I], OutBuffer^, 4 - I);
  777.       Inc(Cardinal(OutBuffer), 4 - I);
  778.       Ctx.LineWritten := 4 - I;
  779.     end;
  780.   end;
  781.   while Size >= 3 do
  782.   begin
  783.     if Ctx.LineSize > 0 then
  784.     begin
  785.       Chunks := (Ctx.LineSize - Ctx.LineWritten) div 4;
  786.       if Chunks > Size div 3 then
  787.         Chunks := Size div 3;
  788.     end
  789.     else
  790.       Chunks := Size div 3;
  791.     for I := 0 to Chunks - 1 do
  792.     begin
  793.       PByte(OutBuffer)^ := Base64Symbols[PByteArray(Buffer)^[0] shr 2];
  794.       Inc(Cardinal(OutBuffer));
  795.       PByte(OutBuffer)^ := Base64Symbols[((PByteArray(Buffer)^[0] and 3) shl 4)
  796.         or (PByteArray(Buffer)^[1] shr 4)];
  797.       Inc(Cardinal(OutBuffer));
  798.       PByte(OutBuffer)^ := Base64Symbols[((PByteArray(Buffer)^[1] and $f) shl 2)
  799.         or (PByteArray(Buffer)^[2] shr 6)];
  800.       Inc(Cardinal(OutBuffer));
  801.       PByte(OutBuffer)^ := Base64Symbols[PByteArray(Buffer)^[2] and $3f];
  802.       Inc(Cardinal(OutBuffer));
  803.       Inc(Cardinal(Buffer), 3);
  804.     end;
  805.     Dec(Size, 3 * Chunks);
  806.     if Ctx.LineSize > 0 then
  807.     begin
  808.       Inc(Ctx.LineWritten, Chunks * 4);
  809.       if (Size >= 3) and (Ctx.LineSize - Ctx.LineWritten > 0) then
  810.       begin
  811.         Ctx.OutBuf[0] := Base64Symbols[PByteArray(Buffer)^[0] shr 2];
  812.         Ctx.OutBuf[1] := Base64Symbols[((PByteArray(Buffer)^[0] and 3) shl 4)
  813.           or (PByteArray(Buffer)^[1] shr 4)];
  814.         Ctx.OutBuf[2] := Base64Symbols[((PByteArray(Buffer)^[1] and $f) shl 2)
  815.           or (PByteArray(Buffer)^[2] shr 6)];
  816.         Ctx.OutBuf[3] := Base64Symbols[PByteArray(Buffer)^[2] and $3f];
  817.         Inc(Cardinal(Buffer), 3);
  818.         Dec(Size, 3);
  819.         I := Ctx.LineSize - Ctx.LineWritten;
  820.         Move(Ctx.OutBuf[0], OutBuffer^, I);
  821.         Inc(Cardinal(OutBuffer), I);
  822.         if Ctx.EOLSize > 0 then
  823.           Move(Ctx.fEOL[0], OutBuffer^, Ctx.EOLSize);
  824.         Inc(Cardinal(OutBuffer), Ctx.EOLSize);
  825.         Move(Ctx.OutBuf[I], OutBuffer^, 4 - I);
  826.         Inc(Cardinal(OutBuffer), 4 - I);
  827.         Ctx.LineWritten := 4 - I;
  828.       end
  829.       else if Ctx.LineWritten = Ctx.LineSize then
  830.       begin
  831.         Ctx.LineWritten := 0;
  832.         if Ctx.EOLSize > 0 then
  833.         begin
  834.           Move(Ctx.fEOL[0], OutBuffer^, Ctx.EOLSize);
  835.           Inc(Cardinal(OutBuffer), Ctx.EOLSize);
  836.         end;
  837.       end;
  838.     end;
  839.   end;
  840.   if Size > 0 then
  841.   begin
  842.     Move(Buffer^, Ctx.Tail[0], Size);
  843.     Ctx.TailBytes := Size;
  844.   end;
  845.   Result := true;
  846. end;
  847. function B64Decode(var Ctx : TSBBase64Context; Buffer : pointer; Size : integer;
  848.   OutBuffer : pointer; var OutSize : integer) : boolean;
  849. var
  850.   I, EstSize, EQUCount : integer;
  851.   BufPtr : pointer;
  852.   C : byte;
  853. begin
  854.   if Size = 0 then
  855.   begin
  856.     Result := true;
  857.     OutSize := 0;
  858.     Exit;
  859.   end;
  860.   EQUCount := Ctx.EQUCount;
  861.   EstSize := Ctx.TailBytes;
  862.   BufPtr := Buffer;
  863.   for I := 0 to Size - 1 do
  864.   begin
  865.     C := Base64Values[PByte(BufPtr)^];
  866.     if C < 64 then Inc(EstSize)
  867.     else if C = $ff then
  868.     begin
  869.       Result := false;
  870.       OutSize := 0;
  871.       Exit;
  872.     end
  873.     else if C = $fd then
  874.     begin
  875.       if EQUCount > 1 then
  876.       begin
  877.         Result := false;
  878.         OutSize := 0;
  879.         Exit;
  880.       end;
  881.       Inc(EQUCount);
  882.     end;
  883.     Inc(Cardinal(BufPtr));
  884.   end;
  885.   EstSize := (EstSize div 4) * 3;
  886.   if OutSize < EstSize then
  887.   begin
  888.     OutSize := EstSize;
  889.     Result := false;
  890.     Exit;
  891.   end;
  892.   Ctx.EQUCount := EQUCount;
  893.   OutSize := EstSize;
  894.   while Size > 0 do
  895.   begin
  896.     C := Base64Values[PByte(Buffer)^];
  897.     if C < 64 then
  898.     begin
  899.       Ctx.Tail[Ctx.TailBytes] := C;
  900.       Inc(Ctx.TailBytes);
  901.       if Ctx.TailBytes = 4 then
  902.       begin
  903.         PByte(OutBuffer)^ := (Ctx.Tail[0] shl 2) or (Ctx.Tail[1] shr 4);
  904.         Inc(Cardinal(OutBuffer));
  905.         PByte(OutBuffer)^ := ((Ctx.Tail[1] and $f) shl 4) or (Ctx.Tail[2] shr 2);
  906.         Inc(Cardinal(OutBuffer));
  907.         PByte(OutBuffer)^ := ((Ctx.Tail[2] and $3) shl 6) or Ctx.Tail[3];
  908.         Inc(Cardinal(OutBuffer));
  909.         Ctx.TailBytes := 0;
  910.       end;
  911.     end;
  912.     Inc(Cardinal(Buffer));
  913.     Dec(Size);
  914.   end;
  915.   Result := true;
  916. end;
  917. function B64FinalizeEncoding(var Ctx : TSBBase64Context;
  918.   OutBuffer : pointer; var OutSize : integer) : boolean;
  919. begin
  920.   if Ctx.TailBytes = 0 then
  921.   begin
  922.     { writing trailing EOL }
  923.     if (Ctx.EOLSize > 0) and (Ctx.LineWritten > 0) then
  924.     begin
  925.       if OutSize < Ctx.EOLSize then
  926.       begin
  927.         OutSize := Ctx.EOLSize;
  928.         Result := false;
  929.       end
  930.       else
  931.       begin
  932.         OutSize := Ctx.EOLSize;
  933.         Result := true;
  934.         Move(Ctx.fEOL[0], OutBuffer^, Ctx.EOLSize);
  935.       end;  
  936.     end
  937.     else
  938.     begin
  939.       OutSize := 0;
  940.       Result := true;
  941.     end;
  942.     Exit;
  943.   end;
  944.   if OutSize < 4 + Ctx.EOLSize then
  945.   begin
  946.     OutSize := 4 + Ctx.EOLSize;
  947.     Result := false;
  948.     Exit;
  949.   end;
  950.   if Ctx.TailBytes = 1 then
  951.   begin
  952.     PByteArray(OutBuffer)^[0] := Base64Symbols[Ctx.Tail[0] shr 2];
  953.     PByteArray(OutBuffer)^[1] := Base64Symbols[((Ctx.Tail[0] and 3) shl 4)];
  954.     PByteArray(OutBuffer)^[2] := $3D; // '='
  955.     PByteArray(OutBuffer)^[3] := $3D; // '='
  956.   end
  957.   else if Ctx.TailBytes = 2 then
  958.   begin
  959.     PByteArray(OutBuffer)^[0] := Base64Symbols[Ctx.Tail[0] shr 2];
  960.     PByteArray(OutBuffer)^[1] := Base64Symbols[((Ctx.Tail[0] and 3) shl 4) or (Ctx.Tail[1] shr 4)];
  961.     PByteArray(OutBuffer)^[2] := Base64Symbols[((Ctx.Tail[1] and $f) shl 2)];
  962.     PByteArray(OutBuffer)^[3] := $3D; // '='
  963.   end;
  964.   if Ctx.EOLSize > 0 then
  965.     Move(Ctx.fEOL[0], PByteArray(OutBuffer)^[4], Ctx.EOLSize);
  966.     
  967.   OutSize := 4 + Ctx.EOLSize;
  968.   Result := true;
  969. end;
  970. function B64FinalizeDecoding(var Ctx : TSBBase64Context;
  971.   OutBuffer : pointer; var OutSize : integer) : boolean;
  972. begin
  973.   if (Ctx.EQUCount = 0) then
  974.   begin
  975.     OutSize := 0;
  976.     Result := Ctx.TailBytes = 0;
  977.     Exit;
  978.   end
  979.   else if (Ctx.EQUCount = 1) then
  980.   begin
  981.     if Ctx.TailBytes <> 3 then
  982.     begin
  983.       Result := false;
  984.       OutSize := 0;
  985.       Exit;
  986.     end;
  987.     if OutSize < 2 then
  988.     begin
  989.       OutSize := 2;
  990.       Result := false;
  991.       Exit;
  992.     end;
  993.     PByte(OutBuffer)^ := (Ctx.Tail[0] shl 2) or (Ctx.Tail[1] shr 4);
  994.     Inc(Cardinal(OutBuffer));
  995.     PByte(OutBuffer)^ := ((Ctx.Tail[1] and $f) shl 4) or (Ctx.Tail[2] shr 2);
  996.     OutSize := 2;
  997.     Result := true;
  998.   end
  999.   else if (Ctx.EQUCount = 2) then
  1000.   begin
  1001.     if Ctx.TailBytes <> 2 then
  1002.     begin
  1003.       Result := false;
  1004.       OutSize := 0;
  1005.       Exit;
  1006.     end;
  1007.     if OutSize < 1 then
  1008.     begin
  1009.       OutSize := 1;
  1010.       Result := false;
  1011.       Exit;
  1012.     end;
  1013.     PByte(OutBuffer)^ := (Ctx.Tail[0] shl 2) or (Ctx.Tail[1] shr 4);
  1014.     OutSize := 1;
  1015.     Result := true;
  1016.   end
  1017.   else
  1018.   begin
  1019.     Result := false;
  1020.     OutSize := 0;
  1021.   end;
  1022. end;
  1023. end.