{ Pascal interface to the crypt() and getpass() functions.

  Copyright (C) 2000-2006 Frank Heckenbach <frank@pascal.gnu.de>

  This file is free software; as a special exception the author
  gives unlimited permission to copy and/or distribute it, with or
  without modifications, as long as this notice is preserved.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY, to the extent permitted by law; without
  even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  PARTICULAR PURPOSE.

  DISCLAIMER: The use and distribution of cryptographic software is
  limited in various countries. Though this unit does not do any
  cryptography itself, it can call cryptographic routines from a
  library. The author disclaims any responsibility for this unit's
  use or distribution. Therefore, before doing anything with this
  unit, please check your applicable laws whether you are allowed to
  do so, and do not use this unit if you are not allowed to or if
  you are not sure whether you are allowed to.

  Note: The functions `Encrypt' and `EncryptWithSalt' use the C
  library's `crypt' function which is not POSIX. If your system's C
  library does not contain such a function, linking any program that
  uses this unit will fail (you might be able to solve the problem
  by linking another library that contains `crypt'). If `crypt' is a
  dummy that returns NULL or an empty string, `Encrypt' and
  `EncryptWithSalt' will cause a runtime error. }

{$gnu-pascal,I-}
{$if __GPC_RELEASE__ < 20030303}
{$error This unit requires GPC release 20030303 or newer.}
{$endif}

unit Crypt;

interface

uses GPC;

{ Encrypt a given key using the given salt. }
function Encrypt (const Key, Salt: String) = Res: TString;

{ Encrypt a given key using a randomly generated salt. }
function EncryptWithSalt (const Key: String): TString;

{ Generate a random "initial" password (not encrypted). }
function MakePassword = Res: TString;

{ Read a password from the terminal invisibly (not encrypted). }
function GetPassword (const Prompt: String): TString;

implementation

{$L cryptc.c}
function Crypt (Key, Salt: CString): CString; external name '_c_crypt';
function GetPasswordC (Prompt: CString): CString; external name '_c_getpass';

function Encrypt (const Key, Salt: String) = Res: TString;
begin
  Res := CString2String (Crypt (Key, Salt));
  if Res = '' then RuntimeErrorCString (ELibraryFunction, 'crypt')
end;

function EncryptWithSalt (const Key: String): TString;
const SaltChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./';
begin
  EncryptWithSalt := Encrypt (Key, SaltChars[Random (Length (SaltChars)) + 1] +
                                   SaltChars[Random (Length (SaltChars)) + 1])
end;

function MakePassword = Res: TString;
{ `I', `l', `1' and perhaps `!' are likely to be confused when printed.
  Same for `O', `o' and `0'. }
const PasswordChars = 'abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789-./;';
var i: Integer;
begin
  Res := '';
  { Don't start or end with a non-alphanumeric character to avoid confusion }
  for i := 1 to 8 do Res := Res + PasswordChars[Random (Length (PasswordChars) - 4 * Ord (i in [1, 8])) + 1]
end;

function GetPassword (const Prompt: String): TString;
var Buf: CString;
begin
  Buf := GetPasswordC (Prompt);
  GetPassword := CString2String (Buf);
  FillChar (Buf^, CStringLength (Buf), 0)
end;

end.
