fmain.pas

来自「著名的SecureBlackBox控件完整源码」· PAS 代码 · 共 453 行

PAS
453
字号
unit fMain;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, SBUtils, SBDomainKeys, ExtCtrls, Clipbrd, SBPEM;

type
  TfrmMain = class(TForm)
    lblStep1: TLabel;
    lblStep3: TLabel;
    lblStep2: TLabel;
    lblStep4: TLabel;
    lblStep5: TLabel;
    lblMessageHeader: TLabel;
    lblMessageBody: TLabel;
    btnLoadMessage: TButton;
    memMessageHeader: TMemo;
    memMessageBody: TMemo;
    lblStep3Result: TLabel;
    btnProcessHeader: TButton;
    dlgOpenMessage: TOpenDialog;
    grpSignatureParameters: TGroupBox;
    grpPrivateKey: TGroupBox;
    lblDomain: TLabel;
    lblSelector: TLabel;
    lblQueryType: TLabel;
    edtDomain: TEdit;
    edtSelector: TEdit;
    cmbQueryType: TComboBox;
    memPrivateKey: TMemo;
    btnPastePrivateKey: TButton;
    btnLoadPrivateKey: TButton;
    dlgOpenPrivateKey: TOpenDialog;
    btnProcessBody: TButton;
    lblStep5Result: TLabel;
    pnlTop: TPanel;
    pnlBottom: TPanel;
    btnReset: TButton;
    lblStep7: TLabel;
    btnSign: TButton;
    lblStep6Result: TLabel;
    lblSignature: TLabel;
    memSignature: TMemo;
    btnSaveMessage: TButton;
    btnSetMethod: TButton;
    lblCanonicalization: TLabel;
    cmbCanonicalization: TComboBox;
    btnSetPrivateKey: TButton;
    lblStep6: TLabel;
    dlgSaveSigned: TSaveDialog;
    lblStep4Notes: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnLoadMessageClick(Sender: TObject);
    procedure btnProcessHeaderClick(Sender: TObject);
    procedure btnPastePrivateKeyClick(Sender: TObject);
    procedure btnLoadPrivateKeyClick(Sender: TObject);
    procedure btnProcessBodyClick(Sender: TObject);
    procedure btnSignClick(Sender: TObject);
    procedure btnSetMethodClick(Sender: TObject);
    procedure btnSetPrivateKeyClick(Sender: TObject);
    procedure btnResetClick(Sender: TObject);
    procedure btnSaveMessageClick(Sender: TObject);
  private
    // Signer
    FSigner: TElDomainKeysSigner;
  public
    { Public declarations }
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  // create an instance of verifier
  FSigner := TElDomainKeysSigner.Create(nil);
  // set default values for combos
  cmbCanonicalization.ItemIndex := 1;
  cmbQueryType.ItemIndex := 0;
  // disable all steps except the first one
  btnSetMethod.Enabled := False;          // step 2
  btnProcessHeader.Enabled := False;      // step 3
  btnSetPrivateKey.Enabled := False;      // step 4
  btnProcessBody.Enabled := False;        // step 5
  btnSign.Enabled := False;               // step 6
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  // destroy the instance of verifier
  FreeAndNil(FSigner);
end;

procedure TfrmMain.btnLoadMessageClick(Sender: TObject);
var
  Text: TStringList;
  I: Integer;
  HeaderDone: Boolean;
  S: string;
begin
  // call Open File Dialog
  if dlgOpenMessage.Execute then
  begin
    // create a temporary string list
    Text := TStringList.Create;
    try
      // load content of the file to the temporary string list
      Text.LoadFromFile(dlgOpenMessage.FileName);
      // iterate the content line by line to separate header and body
      HeaderDone := False;
      for I := 0 to Text.Count - 1 do
      begin
        S := Text[I];
        if not HeaderDone then
        begin
          // header is not loaded yet
          memMessageHeader.Lines.Add(S);
          if S = '' then    // first empty line separates header and body
            HeaderDone := True;
        end
        else
        begin
          // header is loaded already
          memMessageBody.Lines.Add(S);
        end;
      end;
    finally
      Text.Free;
    end;
    // if the message was loaded successfully, enable the next step
    btnSetMethod.Enabled := True;
    // and disable the current step
    btnLoadMessage.Enabled := False;
  end;
end;

procedure TfrmMain.btnSetMethodClick(Sender: TObject);
begin
  // setting up a canonicalization method
  case cmbCanonicalization.ItemIndex of
    0: FSigner.Canonicalization := dkSimple;
    1: FSigner.Canonicalization := dkNoFWS;
  else
    MessageDlg('Invalid Canonicalization Method specified', mtError, [mbOk], 0);
    Exit;
  end;
  // enable the next step
  btnProcessHeader.Enabled := True;
  // and disable the current one
  btnSetMethod.Enabled := False;
end;

procedure TfrmMain.btnProcessHeaderClick(Sender: TObject);
var
  Result: Integer;
begin
  // call the ProcessHeader method if the signer
  Result := FSigner.ProcessHeader(memMessageHeader.Lines);
  if Result = SB_DK_SIGNER_ERROR_SUCCESS then
  begin
    // the ProcessHeader method returned no error
    lblStep3Result.Caption := 'Succeeded. The message can be signed';
    edtDomain.Text := FSigner.Domain;
    // enable the next step
    btnSetPrivateKey.Enabled := True;
    // and disable the current step
    btnProcessHeader.Enabled := False;
    // scroll the form to make Step 4 controls visible
    //ScrollInView(btnSign);
  end
  else
  begin
    // ProcessHeader method returned an error
    case Result of
      SB_DK_SIGNER_ERROR_INVALID_STATE:
        begin
          // returned if the ProcessHeader and ProcessBodyLine
          // methods are called in wrang order; so this error will
          // not be returned in this demo app
          lblStep3Result.Caption := 'Internal error. Press "RESET" to start from top';
        end;
      SB_DK_SIGNER_ERROR_INVALID_HEADER:
        begin
          // returned if signer has failed to parse message header
          lblStep3Result.Caption := 'Invalid header format. Press "RESET" to start from top';
        end;
      SB_DK_SIGNER_ERROR_EMPTY_HEADER:
        begin
          // returned if empty header was passed
          lblStep3Result.Caption := 'Empty message header. Press "RESET" to start from top';
        end;
      SB_DK_SIGNER_ERROR_INVALID_SENDER:
        begin
          // returned if the Sender field of the message is empty
          lblStep3Result.Caption := 'Sender field doesn'' contain any address. Press "RESET" to start from top';
        end;
      SB_DK_SIGNER_ERROR_SEVERAL_SENDERS:
        begin
          // returned if the Sender field of the message contains several addresses
          lblStep3Result.Caption := 'Sender field contains several addresses. Press "RESET" to start from top';
        end;
      SB_DK_SIGNER_ERROR_NO_DOMAIN:
        begin
          // returned if the Sender or From field does not contain a valid address,
          // so the signer has failed to extract a domain name
          lblStep3Result.Caption := 'Failed to extract a domain name. Press "RESET" to start from top';
        end;
      SB_DK_SIGNER_ERROR_NO_AUTHOR:
        begin
          // returned if the message doesn't contain Sender nor From fields
          lblStep3Result.Caption := 'Cannot find the author of the message. Press "RESET" to start from top';
        end;
    else
      // actually the ProcessHeader method returns only the codes handled above,
      // but just in case...
      lblStep3Result.Caption := 'Unknown error. Press "RESET" to start from top';
    end;
    // disable the current step; Reset method of signer must be called
    // to process next message
    btnProcessHeader.Enabled := False;
  end;
end;

procedure TfrmMain.btnPastePrivateKeyClick(Sender: TObject);
begin
  memPrivateKey.Lines.Clear;
  if Clipboard.HasFormat(CF_TEXT) then
    memPrivateKey.Lines.Text := Clipboard.AsText;
end;

procedure TfrmMain.btnLoadPrivateKeyClick(Sender: TObject);
begin
  if dlgOpenPrivateKey.Execute then
  begin
    memPrivateKey.Lines.Clear;
    memPrivateKey.Lines.LoadFromFile(dlgOpenPrivateKey.FileName);
  end;
end;

procedure TfrmMain.btnSetPrivateKeyClick(Sender: TObject);
var
  S, KeyType, Buffer: string;
  Result, BufferSize: Integer;
begin
  // setting the selector
  if edtSelector.Text = '' then
  begin
    MessageDlg('Selector MUST be specified', mtError, [mbOk], 0);
    edtSelector.SetFocus;
    Exit;
  end;
  FSigner.Selector := edtSelector.Text;
  // setting the query type
  case cmbQueryType.ItemIndex of
    0: FSigner.QueryType := dkDNS;
  else
    MessageDlg('Invalid Query Type specified', mtError, [mbOk], 0);
    Exit;
  end;
  // decoding the private key
  S := memPrivateKey.Lines.Text;
  KeyType := '';
  BufferSize := 0;
  // estimate output buffer size
  Result := SBPEM.Decode(@S[1], Length(S), nil, '', BufferSize, KeyType);
  if (Result <> PEM_DECODE_RESULT_NOT_ENOUGH_SPACE) or (BufferSize = 0) then
  begin
    // we expected "Not Enough Space" error but got something different
    MessageDlg('Cannot decode the private key', mtError, [mbOk], 0);
    Exit;
  end;
  if not SameText(KeyType, 'RSA PRIVATE KEY') then
  begin
    // by now only RSA keys can be used
    MessageDlg('RSA private key is expected', mtError, [mbOk], 0);
    Exit;
  end;
  // actually decode the key
  SetLength(Buffer, BufferSize);
  Result := SBPEM.Decode(@S[1], Length(S), @Buffer[1], '', BufferSize, KeyType);
  if (Result <> PEM_DECODE_RESULT_OK) or (BufferSize = 0) then
  begin
    MessageDlg('Failed to decode the private key', mtError, [mbOk], 0);
    Exit;
  end;
  if not FSigner.SetPrivateKey(@Buffer[1], BufferSize) then
  begin
    MessageDlg('Failed to set the private key', mtError, [mbOk], 0);
    Exit;
  end;
  // enable the next step
  btnProcessBody.Enabled := True;
  // and disable the current one
  btnSetPrivateKey.Enabled := False;
  // scroll the form to bottom
  ScrollInView(pnlBottom);
end;

procedure TfrmMain.btnProcessBodyClick(Sender: TObject);
var
  I, Result: Integer;
begin
  // call ProcessBodyLine method of signer for each line of the message body
  for I := 0 to memMessageBody.Lines.Count - 1 do
  begin
    Result := FSigner.ProcessBodyLine(memMessageBody.Lines[I]);
    if Result <> SB_DK_SIGNER_ERROR_SUCCESS then
    begin
      // SB_DK_SIGNER_ERROR_INVALID_STATE code will be returned if
      // ProcessBodyLine is called before ProcessHeader; so this
      // code will not be returned in this demo app
      lblStep5Result.Caption := 'Internal error';
      // disable the current step; Reset method of signer must be called
      // to process next message
      btnProcessBody.Enabled := False;
      Exit;
    end;
  end;
  // the body is processed successfully
  lblStep5Result.Caption := 'Succeeded';
  // enable the next step
  btnSign.Enabled := True;
  // and disable the current one
  btnProcessBody.Enabled := False;
  // scroll the form to bottom
  ScrollInView(pnlBottom);
end;

procedure TfrmMain.btnSignClick(Sender: TObject);
var
  Result: Integer;
begin
  // sign the message
  Result := FSigner.Sign(memSignature.Lines);
  if Result = SB_DK_SIGNER_ERROR_SUCCESS then
  begin
    lblStep6Result.Caption := 'Succeeded';
  end
  else
  begin
    // Sign method returned an error
    case Result of
      SB_DK_SIGNER_ERROR_INVALID_STATE:
        begin
          // returned if Sign method is called before ProcessHeader;
          // so this error code will not be returned in this demo
          lblStep6Result.Caption := 'Internal error';
        end;
      SB_DK_SIGNER_ERROR_NO_SELECTOR:
        begin
          // returned if no Selector was set; this error code
          // will not be returned in this demo
          lblStep6Result.Caption := 'No selector specified';
        end;
      SB_DK_SIGNER_ERROR_NO_DOMAIN:
        begin
          // returned if the ProcessHeader method was unable to determine
          // a domain name to be used to sign the message and returned
          // the corresponding error code; this error code
          // will not be returned in this demo
          lblStep6Result.Caption := 'No domain name specified';
        end;
      SB_DK_SIGNER_ERROR_NO_PRIVATE_KEY:
        begin
          // returned if no private key is set; this error code
          // will not be returned in this demo
          lblStep6Result.Caption := 'No private key is set';
        end;
      SB_DK_SIGNER_ERROR_FAILURE:
        begin
          // the signed has failed while signing the message
          lblStep6Result.Caption := 'Failed to sign the message';
        end;
    else
      // actually the Sign method returns only the codes handled above,
      // but just in case...
      lblStep6Result.Caption := 'Unknown error';
    end;
  end;
  // disable the current step
  btnSign.Enabled := False;
  // scroll the form to bottom
  ScrollInView(pnlBottom);
end;

procedure TfrmMain.btnSaveMessageClick(Sender: TObject);
var
  F: TextFile;
  I: Integer;
begin
  if dlgSaveSigned.Execute then
  begin
    AssignFile(F, dlgSaveSigned.FileName);
    try
      Rewrite(F);
    except
      MessageDlg(Format('Failed to open the file (%s)', [dlgSaveSigned.FileName]), mtError, [mbOk], 0);
      Exit;
    end;
    try
      // the signature must be written before the original message header
      for I := 0 to memSignature.Lines.Count - 1 do
        WriteLn(F, memSignature.Lines[I]);
      // write the original message header
      for I := 0 to memMessageHeader.Lines.Count - 1 do
        WriteLn(F, memMessageHeader.Lines[I]);
      // write the original message body
      for I := 0 to memMessageBody.Lines.Count - 1 do
        WriteLn(F, memMessageBody.Lines[I]);
    finally
      CloseFile(F);
    end;
  end;
end;

procedure TfrmMain.btnResetClick(Sender: TObject);
begin
  // reset the signer
  FSigner.Reset;
  // clear controls
  memMessageHeader.Lines.Clear;
  memMessageBody.Lines.Clear;
  lblStep3Result.Caption := '';
  edtDomain.Text := '';
  lblStep5Result.Caption := '';
  lblStep6Result.Caption := '';
  memSignature.Lines.Clear;
  // enable the first step
  btnLoadMessage.Enabled := True;
  // scroll the form to top
  ScrollInView(pnlTop);
end;


initialization
SetLicenseKey('ADDCD14AD06709806817E0B3D7BFD0A2222D536FE156466C5D5FE65DB5DEAE76' + 
  'FFDEBC07E915A5751C12C01C783958872A38E4A5EDA140E7247E0F2E56442A3C' + 
  'F3E9347AD8FDE52083A0DFC86BC00ECB0FD0CF1B51159A2BCB84F6EA6349EF47' + 
  '5C15A59AFCC55F7C3AAD26C279628B5D91B1DC94BD2385354A70CCA3B76101D9' + 
  'F41C84A639FC3CCE4BA8F0CC4A66DCD150114A3F58C1AD46B7B94643741BC20A' + 
  '8DCA83AB921480951B423CAA19EF1863A47CA2C3422E7E5634BED98939A5AE43' + 
  'DE1E4BAD79E66D8A5C973B3455656C8C9B6FF024FADD6CDA02D0F506D98493C8' + 
  'BD1ED7B237DB75FA31F2C82654490CDDDEE24E19939137B9E1DB05508733B22F');

end.

⌨️ 快捷键说明

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