Cifrado PC1 ( Pukall Cipher 1 ) en Delphi

El cifrado PC1 no es muy conocido, al menos yo nunca había oído hablar de el hasta hace poco. Lo poco que he podido encontrar en Internet sobre el es que fue desarrollado por un tal Alexander PUKALL en el año 1991 y algo de código en C y pascal. El algoritmo tiene una longitud de clave de 128 bits (16 bytes) y tiene como particularidad que el texto cifrado esta compuesto solamente por caracteres de la 'a' a la 'p' por lo que es muy sencillo guárdalo como texto al no aparecer caracteres extraños.

No se si es un buen sistema de cifrado o no, al no encontrar mucha información al respecto en internet, mi unico interés por el viene de que una aplicación con la trabajo habitualmente guarda sus contraseña utilizando este cifrado, así que me he decidido a hacer este pequeño código para poder trabajar con esas contraseñas.

Si a alguien más le resulta útil que lo utilice.

unit Pukall;
 
interface
 
uses
  SysUtils;
 
function Cifrar(Texto, Clave: AnsiString): AnsiString;
function Descifrar(Texto, Clave: AnsiString): AnsiString;
 
implementation
 
type
  TPukallContext = record
    dx: Word;
    si: Word;
    Key: array[0..15] of AnsiChar;
  end;
 
procedure Swap(var W1: Word; var W2: Word);
var
  W: Word;
begin
  W:= W1; W1:= W2; W2:= W;
end;
 
function Assemble(var Context: TPukallContext): Word;
var
  i: Integer;
  ax, bx, cx: Word;
  x1a0: array[0..7] of Word;
begin
  with Context do
  begin
    Result:= 0;
    for i:= 0 to 7 do
    begin
      if i = 0 then
        x1a0[0]:= (ord(Key[0]) shl 8) + ord(Key[1])
      else
        x1a0[i]:= x1a0[i-1] xor ( ( ord(Key[i*2]) shl 8) + ord(Key[(i*2)+1]) );
 
      // "Code" block
      dx:= dx+i;
      ax:= x1a0[i];
      cx:= $015a;
      bx:= $4e35;
      Swap(ax,si);
      Swap(ax,dx);
      if (ax <> 0) then
        ax:= ax*bx;
      Swap(ax,cx);
      if (ax <> 0) then
      begin
        ax:= ax*si;
        inc(cx,ax);
      end;
      Swap(ax,si);
      ax:= ax*bx;
      inc(dx,cx);
      inc(ax);
      x1a0[i]:= ax;
      // End of "Code" block
 
      Result:= Result xor ax xor dx;
    end;
  end;
end;
 
function Cifrar(Texto, Clave: AnsiString): AnsiString;
var
  b: Byte;
  i, j, k: Integer;
  Context: TPukallContext;
begin
  Result:= '';
  // Si no hay nada que cifrar salimos
  if Length(Texto) < 0 then
    Exit;
  // Inicializamos las variables
  FillChar(Context,Sizeof(Context),#0);
  with Context do
  begin
    // Copiamos la clave
    StrLCopy(Key, PAnsiChar(Clave), 16);
    // Para cada elemento de la cadena
    for i:= 1 to Length(Texto) do
    begin
      b:= Ord(Texto[i]);
      // Ciframos este byte
      k:= Assemble(Context);
      // Cambiamos la clave a partir del byte antes de cifrar
      for j:= 0 to 15 do
        Key[j]:= AnsiChar(Ord(Key[j]) xor b);
      // Guardamos el resultado
      b:= b xor (k shr 8) xor (k and $FF);
      Result:= Result + AnsiChar( Ord('a') + (b shr 4) )
        + AnsiChar( Ord('a') + (b and $0F) );
    end;
  end;
end;
 
function Descifrar(Texto, Clave: AnsiString): AnsiString;
var
  b: Byte;
  i, j, k: Integer;
  Context: TPukallContext;
begin
  Result:= '';
  // Si la longitud del texto no es multiplo de 2 salimos
  if Odd(Length(Texto)) then
    Exit;
  // Inicializamos las variables
  FillChar(Context,Sizeof(Context),#0);
  with Context do
  begin
    // Copiamos la clave
    StrLCopy(Key, PAnsiChar(Clave), 16);
    // Tomamos los elementos de dos en dos
    for i:= 0 to (Length(Texto) div 2) - 1 do
    begin
      // Recomponemos el byte a partir de los caracteres
      b:= ((Ord(Texto[(2*i)+1])-Ord('a')) shl 4) + (Ord(Texto[(2*i)+2])-Ord('a'));
      // Desciframos este byte
      k:= Assemble(Context);
      b:= b xor (k shr 8) xor (k and $FF);
      Result:= Result + AnsiChar(b);
      // Modificamos la clave a partir del byte descifrado
      for j:= 0 to 15 do
        Key[j]:= AnsiChar(Ord(Key[j]) xor b);
    end;
  end;
end;
 
end.

Ejemplo de como usarlo:

var
  Str: String;
begin
  Str:= Cifrar('Hola mundo','Clave');
  Writeln('Texto cifrado: ' + Str);
  Str:= Descifrar(Str,'Clave');
  Writeln('Texto descifrado: ' + Str); 
end.

El ejemplo anterior da una salida como esta:

Texto cifrado: agcjjacjmhnibkjajjgi
Texto descifrado: Hola mundo

Comentarios

Me lo guardo :)

Saludos.

Interesante...
Gracias por compartirlo, tal vez lo use.
Saludos.