pgpdecode.pas

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

PAS
1,048
字号
procedure TPGPDecodeCustom.FinitDecode;
begin
  if FKeyPropsList.Count<>0 then KeyRings.UpdateKeyRings;
  with FRecipientsData do begin
    if KeyIDArray<>nil then FreeMem(KeyIDArray);
    PGPFreeKeySet(RecipientSet);
  end;
  if FPassOption=AnalyseOnly then
    PGPFreeContext(FContext)
  else KeyDlgFree(FContext, FtlsContext, FKeySetMain);
end;

function TPGPDecodeCustom.GetOutputFile: String;
var
  FileExtension	: String;
begin
  if FDetachedSigVerify then begin
    if FSignedFileName='' then begin
      FSignedFileName:=Trim(FInputFileName);
      FileExtension:=LowerCase(ExtractFileExt(FSignedFileName));
      if (FileExtension='.sig') or (FileExtension='.asc') then begin
	Delete(FSignedFileName, Length(FSignedFileName)-3, 4);
      end;
    end;
    if ((FSignedFileName=FInputFileName) or not FileExists(FSignedFileName))
    and Assigned(FOnGetSignedFileName) then begin
      FOnGetSignedFileName(FSignedFileName);
    end;
    Result:=FSignedFileName;
  end
  else begin
    if FOutputFileName='' then begin
      FOutputFileName:=Trim(FInputFileName);
      FileExtension:=LowerCase(ExtractFileExt(FOutputFileName));
      if (FileExtension='.pgp') or (FileExtension='.gpg') or (FileExtension='.asc') then begin
	Delete(FOutputFileName, Length(FOutputFileName)-3, 4);
      end;
    end;
    if (FOutputFileName='') or (ExtractFileExt(FOutputFileName)='') or FileExists(FOutputFileName) then begin
      if Assigned(FOnGetOutputFileName) then
	FOnGetOutputFileName(FOutputFileName)
      else FOutputFileName:='';
    end;
    Result:=FOutputFileName;
  end;
end;

function TPGPDecodeCustom.SecureMove: PGPError;
begin
  try
    Result:=PGPReallocData(PGPGetDefaultMemoryMgr,
			   pointer(FSecureBuffer),
			   succ(FSecureBufferSize + FActualOutputSize),
			   kPGPMemoryMgrFlags_Clear);
    if Result=0 then begin
      Move(FAllocatedOutputBuffer[0], FSecureBuffer[FSecureBufferSize], FActualOutputSize);
      inc(FSecureBufferSize, FActualOutputSize);
    end;
  finally
    PGPFreeData(FAllocatedOutputBuffer);
  end;
end;

function TPGPDecodeCustom.ShowSigInfo: PGPError;
var
  Status	: String;
  Source	: String;
  ID		: String;
  Validity	: String;
  Info		: String;
begin
  Result:=0;
  with FSigPropsRec do begin
    if sStatus<>SIGNED_NOT then begin
      // don't change these (constant) PGP strings, see SigEvent.c
      if sStatus=SIGNED_GOOD then
	Status:='Good Signature' + #10
      else Status:='Bad Signature' + #10;
      // these strings may be customized
      if FInputFileName<>'' then begin
	if FDetachedSigVerify then
	  Source:=ExtractFileName(FSignedFileName) + #10
	else Source:=ExtractFileName(FInputFileName) + #10;
      end
      else Source:='(...)' + #10;
      if (sStatus=SIGNED_NO_KEY) or (sUserID='') then
	ID:='(' + sHexID + ')' + #10
      else ID:=sUserID + #10;
      // don't change these (constant) PGP strings, see SigEvent.c
      if sAxiomatic then
	Validity:='Implicit Trust' + #10 + sCreaTimeStr
      else begin
	case sValidity of
	  Validity_Unknown, Validity_Invalid: Validity:='Invalid Key' + #10 + sCreaTimeStr;
	  Validity_Marginal: Validity:='Marginal Key' + #10 + sCreaTimeStr;
	  Validity_Complete: Validity:='Valid Key' + #10 + sCreaTimeStr;
	end;
      end;
      // these strings may be customized
      if sUserID='' then
	Info:=FLogKeyUnknown
      else begin
	if sStatus<>SIGNED_UNKNOWN_ALG then begin
	  if sVerified then begin
	    if sStatus=SIGNED_SIG_EXPIRED then
	      Info:=FLogExpSignature
	    else begin
	      if sRevoked then Info:=FLogKeyRevoked;
	      if sDisabled then Info:=FLogKeyDisabled;
	      if sExpired then Info:=FLogKeyExpired;
	    end;
	  end
	  else Info:=FLogBadSignature;
	end
	else Info:=FLogUnknownAlg;
      end;
      if Info<>'' then  Info:=' (' + Info + ')';
      if not SendPGPlogMsg(FParentHandle, PChar(Status + Source + ID + Validity + Info)) then begin
	Result:=kPGPError_FeatureNotAvailable;
      end;
    end;
  end;
end;

function TPGPDecodeCustom.WriteOutputFile(Output: PChar; OutputSize: DWord): PGPError;
var
  OutputFile	: THandle;
  BytesWritten	: DWord;
begin
  OutputFile:=CreateFile(PChar(FOutputFileName), GENERIC_WRITE, 0, nil, CREATE_ALWAYS,
			 FILE_ATTRIBUTE_ARCHIVE or FILE_FLAG_WRITE_THROUGH, 0);
  if OutputFile<>INVALID_HANDLE_VALUE then begin
    try
      if not WriteFile(OutputFile, Output[0], OutputSize, BytesWritten, nil)
      or (BytesWritten<>OutputSize) then
	Result:=kPGPError_WriteFailed
      else Result:=kPGPError_NoErr;
    finally
      CloseHandle(OutputFile);
    end;
  end
  else Result:=kPGPError_CantOpenFile;
end;

function TPGPDecodeCustom.Analyze(const Input: String; FileSpec: pPGPFileSpec): PGPError;
var
  OptionList	: pPGPOptionList;
begin
  OptionList:=nil;
  Result:=PGPBuildOptionList(FContext, OptionList,
    [
      PGPODiscardOutput(FContext, PGPTrue),
      PGPOEventHandler(FContext, EventHandler, Self)
    ]);
  if Result<>0 then Exit;
  if FileSpec<>nil then begin
    Result:=PGPAppendOptionList(OptionList, [PGPOInputFile(FContext, FileSpec)]);
  end
  else if Input<>'' then begin
    Result:=PGPAppendOptionList(OptionList, [PGPOInputBuffer(FContext, @Input[1], Length(Input))]);
  end;
  if Result<>0 then Exit;
  try
    Result:=pgpEvents.PGPDecode(FContext, OptionList, PGPOLastOption(FContext));
    if Result=kPGPError_UserAbort then Result:=0;
  finally
    PGPFreeOptionList(OptionList);
  end;
end;

function TPGPDecodeCustom.GetOptionList(var OptionList: pPGPOptionList): PGPError;
begin
  Result:=PGPBuildOptionList(FContext, OptionList,
    [
      PGPOKeySetRef(FContext, FKeySetMain),
      PGPOSendNullEvents(FContext, FProgressInterval),
      PGPOPassThroughKeys(FContext, PGPBoolean(PassThrough_Keys in PassThroughOptions)),
      PGPOPassThroughClearSigned(FContext, PGPBoolean(PassThrough_ClearSigned in PassThroughOptions)),
      PGPOPassThroughIfUnrecognized(FContext, PGPBoolean(PassThrough_Unrecognized in PassThroughOptions)),
      PGPOSendEventIfKeyFound(FContext, PGPTrue),
      PGPORecursivelyDecode(FContext, PGPBoolean(FRecursivelyDecode) and 1),
      PGPOEventHandler(FContext, EventHandler, Self)
    ]);
end;

function TPGPDecodeCustom.SetOutputOption(var OptionList: pPGPOptionList): PGPError;
var
  FileSpec	: pPGPFileSpec;
begin
  if FDetachedSigVerify then begin
    if GetOutputFile<>'' then begin
      FileSpec:=nil;
      Result:=PGPNewFileSpecFromFullPath(FContext, PChar(FSignedFileName), FileSpec);
      if Result<>0 then Exit;
      try
	Result:=PGPAppendOptionList(OptionList,
	  [PGPODetachedSig(FContext, PGPOInputFile(FContext, FileSpec), PGPOLastOption(FContext))]);
      finally
	PGPFreeFileSpec(FileSpec);
      end;
    end
    else Result:=kPGPError_DetachedSignatureFound;
  end
  else if FileOutput then begin
    if GetOutputFile<>'' then begin
      Result:=PGPAppendOptionList(OptionList,
	[PGPOAllocatedOutputBuffer(FContext, FAllocatedOutputBuffer, $FFFFFFFF, FActualOutputSize)]);
    end
    else Result:=kPGPError_CantOpenFile;
  end
  else begin
    Result:=PGPAppendOptionList(OptionList,
      [PGPOAllocatedOutputBuffer(FContext, FAllocatedOutputBuffer, $FFFFFFFF, FActualOutputSize)]);
  end;
end;

function TPGPDecodeCustom.Decode(Input: String; IsFile: Longbool): Longint;
var
  BugFix	: Longbool;
  OptionList	: pPGPOptionList;
  FileSpec	: pPGPFileSpec;
  FileHandle	: THandle;
  FileSizeHigh	: DWord;
  Output	: PChar;
  OutputSize	: DWord;
begin
  Result:=0;
  BugFix:=false;
  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;
    Result:=InitDecode;
    if Result<>0 then Exit;
    try
      if IsFile then begin
	Result:=PGPNewFileSpecFromFullPath(FContext, PChar(FInputFileName), FileSpec);
	if Result<>0 then Exit;
      end;
      try
	Result:=Analyze(Input, FileSpec);
	if Result=kPGPError_BadIntegrity then Result:=0; // avoid strange error after kPGPError_SkipSection
	if not FRecognized and (Input<>'') and (Input[1]>#127) then begin // avoid strange decoding error
	  Input:='@' + Input;
	  BugFix:=true;
	  Result:=0;
	end;
	if FPassOption<>AnalyseOnly then begin
	  if Result<>0 then Exit;
	  Result:=GetOptionList(OptionList);
	  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;
	  try
	    if Result<>0 then Exit;
	    if FDetachedSigVerify or FClearSigned then begin
	      Result:=SetOutputOption(OptionList);
	      if Result<>0 then Exit;
	    end
	    else FOutputExists:=false;
	    FPassOption:=DecodePass;
	    Result:=pgpEvents.PGPDecode(FContext, OptionList, PGPOLastOption(FContext));
	    try
	      if (FPassOption<>AnalyseOnly) and (Result=0) then begin
		if not (FDetachedSigVerify or FClearSigned) then begin
		  Result:=SecureMove;
		  if Result<>0 then Exit;
		  FAllocatedOutputBuffer:=FSecureBuffer;
		  FActualOutputSize:=FSecureBufferSize;
		  if BugFix and (PassThrough_Unrecognized in PassThroughOptions) then begin // remove leading AT
		    Output:=FAllocatedOutputBuffer + 1;
		    OutputSize:=pred(FActualOutputSize);
		  end
		  else begin // AT already removed
		    Output:=FAllocatedOutputBuffer;
		    OutputSize:=FActualOutputSize;
		  end;
		  if FEyesOnly then begin
		    Result:=TempestViewer(FContext, FParentHandle, Output, OutputSize, true);
		    ProcessMessages;
		    Exit;
		  end;
		end
		else begin
		  if BugFix and (PassThrough_Unrecognized in PassThroughOptions) then begin // remove leading AT
		    Output:=FAllocatedOutputBuffer + 1;
		    OutputSize:=pred(FActualOutputSize);
		  end
		  else begin // AT already removed
		    Output:=FAllocatedOutputBuffer;
		    OutputSize:=FActualOutputSize;
		  end;
		end;
		if FileOutput then
		  WriteOutputFile(Output, OutputSize)
		else begin
		  SetLength(FOutputBuffer, OutputSize);
		  Move(Output[0], FOutputBuffer[1], OutputSize);
		end;
	      end;
	    except
	      on EOutOfMemory do Result:=kPGPError_OutOfMemory;
	    end;
	  finally
	    try
	      PGPFreeOptionList(OptionList);
	    finally
	      try
		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;
	  end;
	end;
      finally
	PGPFreeFileSpec(FileSpec);

⌨️ 快捷键说明

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