Hace tiempo que no pongo código por aquí, al menos no
código útil, así que vamos a ver que os parece esta pequeña herramienta.
Se trata de una aplicación de consola que permite subir o bajar un archivo de un servidor ftp, pero con la particularidad que lo cifra al subirlo y lo descifra al bajarlo. El cifrado que utiliza es AES de 256 bits, que nos permite usar contraseñas de hasta 32 caracteres, y es lo suficientemente seguro para que lo utilice el gobierno de los EE.UU.
Pero dije que este no era código inútil, así que vamos a buscarle alguna utilidad. La primera, y mas evidente, es subir un archivo:
Código:
ftpup --key=clave --local=archivo.txt --password=pass --user=user --remote=/archivo.txt --server=servidor.com
El comando anterior subiría el archivo "archivo.txt" al servidor "servidor.com", usando el nombre de usuario "user", el password "pass" y la clave de cifrado "clave". Hasta ahora nada que no se pudiera hacer con cualquier otro cliente de ftp, salvo el cifrado. Se me ocurre que puede servir para hacer una copia de seguridad de un documento privado, si lo combinamos, por ejemplo, con las tareas programadas de Windows.
Para bajarlo, nada mas sencillo que esto:
Código:
ftpup -d --key=clave --local=archivo.txt --password=pass --user=user --remote=/archivo.txt --server=servidor.com
Pero ya me conocéis, hay que buscar otro uso mas interesante a esto, darle otra vuelta de tuerca. Que os parece utilizarlo para guardar, y leer, anotaciones cifradas desde cualquier ordenador, sin dejar ningún rastro en el equipo. Pues vamos a probar, lo primero es decir que en el parámetro --local se puede usar un "." para decir que se utilice en vez de un archivo, la entrada y salida estándar. Sabiendo esto, podríamos hacer algo como esto:
Código:
echo Mensaje secreto | ftpup --key=clave --local=. --password=pass --user=user --remote=/archivo.txt --server=servidor.com
Y para leerlo algo como esto:
Código:
ftpup -d --key=clave --local=. --password=pass --user=user --remote=/archivo.txt --server=servidor.com
Y ya puestos, podríamos guardar cómodamente nuestras contraseñas en un archivo de texto, y desde nuestra casa subirlas al ftp. Así desde cualquier equipo en el que estemos podremos ver las contraseñas en pantalla, si necesidad de guardar ningún archivo en el disco.
Bueno, seguro que alguna utilidad mas se le puede sacar. Como siempre, criticas (constructivas) y sugerencias serán bien recibidas. Espero vuestros comentarios.
El código (es una aplicación de consola):
Código Delphi
[-]
program ftpup;
{$APPTYPE CONSOLE}
uses
Windows,
SysUtils,
Classes,
WinInet,
AES in 'AES.pas';
type
EGetOptError = class(Exception);
var
Options: record
Download: Boolean;
Key: String;
Local: String;
Password: String;
Port: Integer;
Remote: String;
Server: String;
User: String;
end;
function Starts(Sub, Str: String): Boolean;
begin
Result:= SameText(Sub,Copy(Str,1,Length(sub)));
end;
procedure Getopt;
var
i,j: Integer;
Str: String;
begin
FillChar(Options,Sizeof(Options),#0);
for i:= 1 to ParamCount do
begin
Str:= ParamStr(i);
if (Copy(Str,1,2) = '--') and (Length(Str) > 2) then
begin
if SameText(Str,'--Download') then
Options.Download:= TRUE
else if Starts('--Key=',Str) then
begin
if Options.Key = EmptyStr then
Options.Key:= Copy(Str,Length('--Key=') + 1,MAXINT)
else
raise EGetOptError.Create(Str);
end else if Starts('--Local=',Str) then
begin
if Options.Local = EmptyStr then
Options.Local:= Copy(Str,Length('--Local=') + 1,MAXINT)
else
raise EGetOptError.Create(Str);
end else if Starts('--Remote=',Str) then
begin
if Options.Remote = EmptyStr then
Options.Remote:= Copy(Str,Length('--Remote=') + 1,MAXINT)
else
raise EGetOptError.Create(Str);
end else if Starts('--Password=',Str) then
begin
if Options.Password = EmptyStr then
Options.Password:= Copy(Str,Length('--Password=') + 1,MAXINT)
else
raise EGetOptError.Create(Str);
end else if Starts('--Port=',Str) then
begin
if Options.Port = 0 then
Options.Port:= StrToInt(Copy(Str,Length('--Port=') + 1,MAXINT))
else
raise EGetOptError.Create(Str);
end else if Starts('--Server=',Str) then
begin
if Options.Server = EmptyStr then
Options.Server:= Copy(Str,Length('--Server=') + 1,MAXINT)
else
raise EGetOptError.Create(Str);
end else if Starts('--User=',Str) then
begin
if Options.User = EmptyStr then
Options.User:= Copy(Str,Length('--User=') + 1,MAXINT)
else
raise EGetOptError.Create(Str);
end else
raise EGetOptError.Create(Str);
end else if (Copy(Str,1,1) = '-') and (Length(Str) > 1) then
begin
Str:= UpperCase(Str);
for j:= 2 to Length(Str) do
begin
if Str[j] = 'D' then
Options.Download:= TRUE
else
raise EGetOptError.Create(Str);
end;
end else
begin
raise EGetOptError.Create(Str);
end;
end;
if Options.Port = 0 then
Options.Port:= 21;
end;
function ftpUpload(Stream: TStream; RemoteFile, Server: String; Port: Word;
Username, Password: PChar; Key: TAESExpandedKey): Boolean;
var
hNet: HINTERNET;
hCon: HINTERNET;
hFile: HINTERNET;
Context: DWORD;
Count: Cardinal;
State, Temp: TAESState;
Size: int64;
begin
Result := FALSE;
Context:= 0;
hNet := InternetOpen('agent', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if (hNet <> nil) then
begin
hCon:= InternetConnect(hNet,PChar(Server),Port,Username,Password,
INTERNET_SERVICE_FTP,0,Context);
if (hCon <> nil) then
begin
hFile:= FtpOpenFile(hCon,PChar(RemoteFile),GENERIC_WRITE,
FTP_TRANSFER_TYPE_BINARY,Context);
if hFile <> nil then
begin
try
if Stream is TFileStream then
Size:= Stream.Size
else
Size:= -1;
if InternetWriteFile(hFile,@Size,Sizeof(Size),Count) and
(Count = Sizeof(Size)) then
begin
FillChar(Temp,Sizeof(Temp),#0);
FillChar(State,Sizeof(State),#0);
Count:= Stream.Read(State,Sizeof(State));
while Count > 0 do
begin
XORState(State,Temp);
AESEncrypt(State,Key);
if not InternetWriteFile(hFile,@State,Sizeof(State),Count) then
break;
Temp:= State;
FillChar(State,Sizeof(State),#0);
Count:= Stream.Read(State,Sizeof(State));
end;
Result:= Count = 0;
end;
if not Result then
Writeln(SysErrorMessage(GetLastError));
except
On E: Exception do
Writeln(E.Message);
end;
InternetCloseHandle(hFile);
end else Writeln(SysErrorMessage(GetLastError));
InternetCloseHandle(hCon);
end else Writeln(SysErrorMessage(GetLastError));
InternetCloseHandle(hNet);
end else Writeln(SysErrorMessage(GetLastError));
end;
function ftpDownload(Stream: TStream; RemoteFile, Server: String; Port: Word;
Username, Password: PChar; Key: TAESExpandedKey): Boolean;
var
hNet: HINTERNET;
hCon: HINTERNET;
hFile: HINTERNET;
Context: DWORD;
Count: Cardinal;
State, Temp, Ant: TAESState;
Size: int64;
begin
Result := FALSE;
Context:= 0;
hNet := InternetOpen('agent', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
if (hNet <> nil) then
begin
hCon:= InternetConnect(hNet,PChar(Server),Port,Username,Password,
INTERNET_SERVICE_FTP,0,Context);
if (hCon <> nil) then
begin
hFile:= FtpOpenFile(hCon,PChar(RemoteFile),GENERIC_READ,
FTP_TRANSFER_TYPE_BINARY,Context);
if hFile <> nil then
begin
try
if InternetReadFile(hFile,@Size,Sizeof(Size),Count) and
(Count = Sizeof(Size)) then
begin
FillChar(Temp,Sizeof(Temp),#0);
FillChar(State,Sizeof(State),#0);
if InternetReadFile(hFile,@State,Sizeof(State),Count) then
begin
while Count > 0 do
begin
Ant:= State;
AESDecrypt(State,Key);
XORState(State,Temp);
if Stream.Write(State,Count) <> Integer(Count) then
break;
Temp:= Ant;
FillChar(State,Sizeof(State),#0);
if not InternetReadFile(hFile,@State,Sizeof(State),Count) then
break;
end;
Result:= Count = 0;
end;
if (Stream is TFileStream) and (Stream.Size > Size)
and (Size > 0 )then
Stream.Size:= Size;
if not Result then
Writeln(SysErrorMessage(GetLastError));
end;
except
On E: Exception do
Writeln(E.Message);
end;
InternetCloseHandle(hFile);
end else Writeln(SysErrorMessage(GetLastError));
InternetCloseHandle(hCon);
end else Writeln(SysErrorMessage(GetLastError));
InternetCloseHandle(hNet);
end else Writeln(SysErrorMessage(GetLastError));
end;
procedure Run;
var
AESKey: TAESKey;
ExKey: TAESExpandedKey;
Stream: TStream;
begin
FillChar(AESKey,Sizeof(AESKey),#0);
if Length(Options.Key) > Sizeof(AESKey) then
move(PChar(Options.Key)^,AESKey,Sizeof(AESKey))
else
move(PChar(Options.Key)^,AESKey,Length(Options.Key));
AESExpandKey(ExKey,AESKey);
if Options.Local = '.' then
begin
if Options.Download then
Stream:= THandleStream.Create(GetStdHandle(STD_OUTPUT_HANDLE))
else
Stream:= THandleStream.Create(GetStdHandle(STD_INPUT_HANDLE));
end else
begin
if Options.Download then
Stream:= TFileStream.Create(Options.Local,fmCreate)
else
Stream:= TFileStream.Create(Options.Local,fmOpenRead or fmShareDenyNone);
end;
try
if Options.Download then
ftpDownload(Stream,Options.Remote,Options.Server,Options.Port,
PChar(Options.User),PChar(Options.Password),ExKey)
else
ftpUpload(Stream,Options.Remote,Options.Server,Options.Port,
PChar(Options.User),PChar(Options.Password),ExKey)
finally
Stream.Free;
end;
end;
procedure Help;
begin
Writeln;
Writeln('Uso: ftpup [opciones]');
Writeln(' --download -d');
Writeln(' Baja el archivo del servidor');
Writeln(' --key');
Writeln(' Clave de cifrado, hasta 32 caracteres.');
Writeln(' --local');
Writeln(' Archivo local. Se puede utilizar un . para indicar la');
Writeln(' entrada o salida estandar');
Writeln(' --password');
Writeln(' Clave de acceso al servidor ftp');
Writeln(' --port');
Writeln(' El puerto del ftp');
Writeln(' --remote');
Writeln(' Ruta del archivo remoto');
Writeln(' --server');
Writeln(' Direccion del servidor ftp');
Writeln(' --user');
Writeln(' Nombre de usuario del ftp');
Writeln;
Writeln('Ejemplos:');
Writeln(' ftpup --key=clave --local=archivo.txt --password=pass ' +
'--user=user --remote=/archivo.txt --server=servidor.com');
Writeln(' Sube al servidor el archivo "archivo.txt".');
Writeln(' ftpup -d --key=clave --local=. --password=pass ' +
'--user=user --remote=/archivo.txt --server=servidor.com');
Writeln(' Descarga el archivo "archivo.txt" y lo muestra por pantalla');
Writeln;
end;
begin
try
if ParamCount > 0 then
begin
GetOpt;
Run;
end else
Help;
except
On E: EGetOptError do
begin
Writeln('Error en el parametro: ',E.Message);
Help;
end;
On E: Exception do
Writeln(E.Message);
end;
end.