pgpencode.pas

来自「用DELPHI实现的 PGP 加密算法」· PAS 代码 · 共 857 行 · 第 1/2 页

PAS
857
字号
	    KeyPropsList.Free;
	  end;
	end;
      finally
	PGPFreeKeySet(pPGPKeySet(RecipientKeys));
      end;
    end;
  end
  else if FEncryptToSelf and (EncryptKeyIDs.Count<>0) then EncryptKeyIDs.Add(SignKeyID);
end;

function GetPGPHashAlgorithm(SignAlgorithm: TSignAlgorithm): PGPHashAlgorithm;
begin
  Result:=PGPHashAlgorithm(
    ord(SignAlgorithm) +
    ord(SignAlgorithm>HashAlgorithm_RIPEMD160) * ord(pred(kPGPHashAlgorithm_SHA256-kPGPHashAlgorithm_RIPEMD160))
  );
end;

function TPGPEncodeCustom.GetOptionList(var OptionList: pPGPOptionList): PGPError;
var
  Cancel	: Longbool;
  KeyPropsList	: TKeyPropsList;
  BadPassphrase	: Longbool;
  SelectedKey	: Longint;
  SignKeyHexID	: String;
  SigningKey	: pPGPKey;
  AlgorithmList	: TPGPCipherAlgorithms;
  AlgCount	: Longint;
  Armor		: PGPUInt32;
  MIME		: PGPUInt32;
  Textmode	: PGPUInt32;
  RipeMD	: PGPUInt32; 
begin
  Cancel:=false;
  FPassphraseBufSize:=MaxUTF8Length;
  KeyPropsList:=TKeyPropsList.Create(0, spgpKeyPropFlag_IDComplete);
  try
    if FDetachedSign then begin
      Result:=PGPBuildOptionList(FContext, OptionList,
	[
	  PGPOSendNullEvents(FContext, FProgressInterval),
	  PGPOEventHandler(FContext, EventHandler, Self),
	  PGPOArmorOutput(FContext, PGPBoolean(Format_Armor in FFormatOptions)),
	  PGPODetachedSig(FContext, PGPOLastOption(FContext), nil),
	  PGPOCommentString(FContext, PChar(FComment)),
	  PGPOVersionString(FContext, MyVersion)
	]);
    end
    else begin
      Result:=PGPBuildOptionList(FContext, OptionList,
	[
	  PGPOSendNullEvents(FContext, FProgressInterval),
	  PGPOEventHandler(FContext, EventHandler, Self),
	  PGPOClearSign(FContext, PGPBoolean(FClear) and 1),
	  PGPOCompression(FContext, PGPBoolean(FCompress) and 1),
	  PGPOCommentString(FContext, PChar(FComment)),
	  PGPOVersionString(FContext, MyVersion)
	]);
    end;
    if Result<>0 then Exit;
    BadPassphrase:=false;
    if FConventional then begin
      Result:=PGPAppendOptionList(OptionList,
	[PGPOCipherAlgorithm(FContext, PGPCipherAlgorithm(succ(FConventionalAlgorithm)))]);
      if Result<>0 then Exit;
      if Assigned(FOnEnterPassphrase) then begin
	SelectedKey:=-1;
	FPassphrase:=PGPNewSecureData(PGPGetDefaultMemoryMgr, FPassphraseBufSize, kPGPMemoryMgrFlags_Clear);
	if FPassphrase<>nil then begin
	  Result:=kPGPError_UserAbort;
	  FOnEnterPassphrase(FPassphrase, KeyPropsList, SelectedKey, BadPassphrase, Cancel);
	  if not Cancel then begin
	    if PGP8X then AnsiToUtf8PChar(FPassphrase, FPassphrase, FPassphraseBufSize);
	  end
	  else Exit;
	end
	else begin
	  Result:=kPGPError_OutOfMemory;
	  Exit;
	end;
      end
      else begin
	Result:=ConvEncPassphraseDialog(FContext, FPassphrase, FPassDlgPrompt, FParentHandle);
	if Result<>0 then Exit;
      end;
      Result:=PGPAppendOptionList(OptionList,
	[PGPOConventionalEncrypt(FContext, PGPOPassphrase(FContext, FPassphrase), PGPOLastOption(FContext))]);
      if Result<>0 then Exit;
    end
    else begin
      SigningKey:=nil;
      if FSign or FDetachedSign then begin
	Armor:=ord(Format_Armor in FFormatOptions);
	MIME:=ord(Format_MIME in FFormatOptions);
	Textmode:=ord(Format_Textmode in FFormatOptions);
	if Assigned(FOnEnterPassphrase) then begin
	  if FindKeyProps('', KeyPropsList, spgpKeyPropFlag_IDComplete,
			  KeyFilterFlag_CanSign, UserID_Ordering)>0 then begin
	    Result:=GetHexIDByAnyID(FContext, FKeySetMain, FSignKeyID, SignKeyHexID);
	    if Result<>1 then with FPreferences do begin
	      if DefaultKeyHexID<>'' then begin
		FSignKeyID:=DefaultKeyHexID;
		Result:=1;
	      end;
	    end
	    else FSignKeyID:=SignKeyHexID;
	    if Result=1 then with KeyPropsList do begin
	      SelectedKey:=IndexOf(FSignKeyID);
	      if SelectedKey>0 then Move(SelectedKey, 0);
	    end;
	  end
	  else begin
	    Result:=kPGPError_SecretKeyNotFound;
	    Exit;
	  end;
	  SelectedKey:=0;
	  FPassphrase:=PGPNewSecureData(PGPGetDefaultMemoryMgr, 256, kPGPMemoryMgrFlags_Clear);
	  if FPassphrase<>nil then begin
	    Result:=kPGPError_UserAbort;
	    repeat
	      FOnEnterPassphrase(FPassphrase, KeyPropsList, SelectedKey, BadPassphrase, Cancel);
	      if not Cancel then begin
		if PGP8X then AnsiToUtf8PChar(FPassphrase, FPassphrase, FPassphraseBufSize);
		if (SelectedKey>=0) and (SelectedKey<KeyPropsList.Count) then begin
		  FSignKeyID:=KeyPropsList[SelectedKey];
		  BadPassphrase:=not PassphraseIsValid(FContext, FKeySetMain, PChar(FSignKeyID), FPassphrase);
		end
		else begin
		  Result:=kPGPError_SecretKeyNotFound;
		  Exit;
		end;
	      end;
	    until Cancel or not BadPassphrase;
	    if Cancel then Exit;
	  end
	  else begin
	    Result:=kPGPError_OutOfMemory;
	    Exit;
	  end;
	  Result:=GetKeyByHexID(FKeySetMain, PChar(FSignKeyID), SigningKey);
	  if Result<>0 then Exit;
	end
	else begin
	  if (FSignKeyID='')
	  or (FindKeyProps(FSignKeyID, KeyPropsList,
			   spgpKeyPropFlag_KeyID,
			   KeyFilterFlag_CanSign,
			   Any_Ordering)<>1) then begin
	    FSignKeyID:=FPreferences.DefaultKeyHexID;
	  end;
	  RipeMD:=ord(FSignAlgorithm=HashAlgorithm_RIPEMD160);
	  Result:=SigningPassphraseDialog(FContext, FKeySetMain, SigningKey, FPassphrase, FSignKeyID, true,
					  TSignOption((ord(FClear) and 1)*ord(soClear) +
						      (ord(FDetachedSign) and 1)*ord(soDetached)),
					  Armor, MIME, RipeMD, FPassDlgPrompt, FParentHandle);
	  if Result<>0 then Exit;
	  if not FEncrypt then begin
	    FFormatOptions:=[];
	    if Armor<>0 then Include(FFormatOptions, Format_Armor);
	    if MIME<>0 then Include(FFormatOptions, Format_MIME);
	    if Textmode<>0 then Include(FFormatOptions, Format_Textmode);
	  end;
	  if RipeMD<>0 then FSignAlgorithm:=HashAlgorithm_RIPEMD160;
	end;
	if FSignAlgorithm=HashAlgorithm_Default then begin
	  case GetKeyPropAlg(SigningKey) of
	    KeyAlgorithm_RSA..KeyAlgorithm_RSASignOnly: if GetKeyPropLegacy(SigningKey) then
	      FSignAlgorithm:=HashAlgorithm_MD5
	    else FSignAlgorithm:=HashAlgorithm_SHA;
	    KeyAlgorithm_DH..KeyAlgorithm_DHDSS: FSignAlgorithm:=HashAlgorithm_SHA;
	  else
	    Result:=kPGPError_UnknownPublicKeyAlgorithm;
	    Exit;
	  end;
	end;
	Result:=PGPAppendOptionList(OptionList,
	  [
	    PGPOSignWithKey(FContext, SigningKey, PGPOPassphrase(FContext, FPassphrase), PGPOLastOption(FContext)),
	    PGPOHashAlgorithm(FContext, GetPGPHashAlgorithm(FSignAlgorithm))
	  ]);
	if Result<>0 then Exit;
      end;
      if SigningKey<>nil then FSignKeyID:=GetKeyPropKeyID(SigningKey);
      if FEncrypt then begin
	Result:=GetEncryptKeyIDs(FEncryptKeyIDs, FSignKeyID);
	if Result<>0 then Exit;
	Result:=GetKeySetByAnyIDs(FContext, FKeySetMain, FEncryptKeyIDs.CommaText, FEncryptKeySet);
	if Result<>0 then Exit;
	Result:=PGPAppendOptionList(OptionList, [PGPOEncryptToKeySet(FContext, FEncryptKeySet)]);
	if Result<>0 then Exit;
	if GetAllowedCipherAlgorithms(AlgorithmList, AlgCount)=0 then begin
	  PGPAppendOptionList(OptionList, [PGPOPreferredAlgorithms(FContext, AlgorithmList, AlgCount)]);
	end;
      end;
    end;
    if not FDetachedSign then begin
      Result:=PGPAppendOptionList(OptionList,
	[
	  PGPOForYourEyesOnly(FContext, PGPBoolean(FEyesOnly) and 1),
	  PGPOArmorOutput(FContext, PGPBoolean(Format_Armor in FFormatOptions)),
	  PGPODataIsASCII(FContext, PGPBoolean(Format_Textmode in FFormatOptions))
	]);
      if Result<>0 then Exit;
      if Format_Mime in FFormatOptions then begin
	SetLength(FMimeSeparator, SizeOf(TMimeSeparator));
	FMimeBodyOffset:=0;
	FMimeSeparator[1]:=#0;
	Result:=PGPAppendOptionList(OptionList,
	  [
	    PGPOPGPMIMEEncoding(FContext, PGPTrue, PGPSize(FMimeBodyOffset), @FMimeSeparator[1]),
	    PGPOOmitMIMEVersion(fContext, PGPBoolean(FOmitMimeVersion) and 1)
	  ]);
	if Result<>0 then Exit;
      end;
    end;
  finally
    KeyPropsList.Free;
  end;
end;

function TPGPEncodeCustom.SetOutputOption(var OptionList: pPGPOptionList): PGPError;
begin
  if FFileOutput then begin
    if (FOutputFileName='') or FileExists(FOutputFileName) then begin
      if FOutputFileName='' then begin
	if FDetachedSign then
	  FOutputFileName:=FInputFileName + '.sig'
	else begin
	  if Format_Armor in FFormatOptions then
	    FOutputFileName:=FInputFileName + '.asc'
	  else FOutputFileName:=FInputFileName + '.pgp';
	end;
      end;
      if Assigned(FOnGetOutputFileName) then
	FOnGetOutputFileName(FOutputFileName)
      else FOutputFileName:='';
    end;
    if FOutputFileName='' then begin
      Result:=kPGPError_CantOpenFile;
      Exit;
    end;
  end;
  Result:=PGPAppendOptionList(OptionList,
    [PGPOAllocatedOutputBuffer(FContext, FAllocatedOutputBuffer, $FFFFFFFF, FActualOutputSize)]);
end;

function TPGPEncodeCustom.Encode(const Input: String; IsFile: Longbool): Longint;
var
  OptionList	: pPGPOptionList;
  FileSpec	: pPGPFileSpec;
  FileHandle	: THandle;
  FileSizeHigh	: DWord;
begin
  Result:=0;
  if IsFile then begin
    FInputFileName:=Input;
    if not FileExists(FInputFileName) then begin
      if Assigned(FOnGetInputFileName) then begin
	FOnGetInputFileName(FInputFileName);
	if FInputFileName='' then Result:=kPGPError_FileNotFound;
      end
      else Result:=kPGPError_FileNotFound;
    end;
  end
  else if Input='' then Result:=kPGPError_ItemNotFound;
  if Result=0 then begin
    FileSpec:=nil;
    OptionList:=nil;
    FEncryptKeySet:=nil;
    Result:=InitEncode;
    if Result<>0 then Exit;
    try
      if IsFile then begin
	Result:=PGPNewFileSpecFromFullPath(FContext, PChar(FInputFileName), FileSpec);
	if Result<>0 then Exit;
      end;
      try
	Result:=GetOptionList(OptionList);
	try
	  if Result<>0 then Exit;
	  if IsFile then begin
	    FileHandle:=FileOpen(FInputFileName, fmOpenRead or fmShareDenyNone);
	    if FileHandle<>INVALID_HANDLE_VALUE then begin
	      FInputSize:=GetFileSize(FileHandle, @FileSizeHigh);
	      FileClose(FileHandle);
	    end
	    else FInputSize:=$FFFFFFFF;
	    if (FInputSize=0) or (FInputSize=$FFFFFFFF) or (FileSizeHigh<>0) then begin
	      Result:=kPGPError_ReadFailed;
	      Exit;
	    end;
	    Result:=PGPAppendOptionList(OptionList, [PGPOInputFile(FContext, FileSpec)]);
	  end
	  else begin
	    FInputSize:=Length(Input);
	    Result:=PGPAppendOptionList(OptionList, [PGPOInputBuffer(FContext, @Input[1], FInputSize)]);
	  end;
	  if Result<>0 then Exit;
	  Result:=SetOutputOption(OptionList);
	  if Result<>0 then Exit;
	  Result:=pgpEvents.PGPEncode(FContext, OptionList, PGPOLastOption(FContext));
	  try
	    if (Result=0) and (FActualOutputSize<>0) then begin
	      if FFileOutput then
		Result:=WriteOutputFile
	      else begin
		SetLength(FOutputBuffer, FActualOutputSize);
		Move(FAllocatedOutputBuffer[0], FOutputBuffer[1], FActualOutputSize);
	      end;
	    end;
	  except
	    on EOutOfMemory do Result:=kPGPError_OutOfMemory;
	  end;
	finally
	  try
	    SetLength(FMimeSeparator, StrLen(PChar(FMimeSeparator)));
	    PGPFreeOptionList(OptionList);
	    PGPFreeKeySet(FEncryptKeySet);
	    if Assigned(FOnWipePassphrase) then begin
	      if PGP8X then begin
		FPassphraseBufSize:=MaxUTF8Length;
		Utf8ToAnsiPChar(FPassphrase, FPassphrase, FPassphraseBufSize);
	      end;
	      FOnWipePassphrase(FPassphrase);
	    end;
	  finally
	    PGPFreeData(FAllocatedOutputBuffer);
	    PGPFreeData(FPassphrase);
	    FPassphrase:=nil;
	  end;
	end;
      finally
	PGPFreeFileSpec(FileSpec);
      end;
    finally
      FinitEncode;
    end;
  end;
end;

function TPGPEncodeCustom.KeyEncryptBuffer(const DataBuffer: String; Sign: Longbool): Longint;
begin
  SetSign(Sign);
  SetEncrypt(true);
  FCompress:=true;
  Result:=Encode(DataBuffer, false);
end;

function TPGPEncodeCustom.KeyEncryptFile(const FileName: String; Sign: Longbool): Longint;
begin
  SetSign(Sign);
  SetEncrypt(true);
  FCompress:=true;
  Result:=Encode(FileName, true);
end;

function TPGPEncodeCustom.ConventionalEncryptBuffer(const DataBuffer: String): Longint;
begin
  FCompress:=true;
  SetConventional(true);
  Result:=Encode(DataBuffer, false);
end;

function TPGPEncodeCustom.ConventionalEncryptFile(const FileName: String): Longint;
begin
  FCompress:=true;
  SetConventional(true);
  Result:=Encode(FileName, true);
end;

function TPGPEncodeCustom.ClearSignBuffer(const DataBuffer: String): Longint;
begin
  SetClear(true);
  Result:=Encode(DataBuffer, false);
end;

function TPGPEncodeCustom.ClearSignFile(const FileName: String): Longint;
begin
  SetClear(true);
  Result:=Encode(FileName, true);
end;

function TPGPEncodeCustom.ArmorBuffer(const DataBuffer: String): Longint;
begin
  FClear:=false;
  FCompress:=true;
  FDetachedSign:=false;
  FEncrypt:=false;
  FSign:=false;
  Include(FFormatOptions, Format_Armor);
  Result:=Encode(DataBuffer, false);
end;

function TPGPEncodeCustom.ArmorFile(const FileName: String): Longint;
begin
  FClear:=false;
  FCompress:=true;
  FDetachedSign:=false;
  FEncrypt:=false;
  FSign:=false;
  Include(FFormatOptions, Format_Armor);
  Result:=Encode(FileName, true);
end;

function TPGPEncodeCustom.DetachedSignBuffer(const DataBuffer: String): Longint;
begin
  FClear:=false;
  FConventional:=false;
  FEncrypt:=false;
  FSign:=false;
  FDetachedSign:=true;
  Result:=Encode(DataBuffer, false);
end;

function TPGPEncodeCustom.DetachedSignFile(const FileName: String): Longint;
begin
  FClear:=false;
  FConventional:=false;
  FEncrypt:=false;
  FSign:=false;
  FDetachedSign:=true;
  Result:=Encode(FileName, true);
end;

end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?