Boletín Pascal #17
Los ejemplos completos de código fuente de este número están disponibles para descargar.
![]() |
![]() |
Boletín Pascal #17 - 20-FEB-2001 INDICE 1. UNAS PALABRAS DEL EDITOR 2. INTRODUCCION A LA PROGRAMACION DE CRIPTOGRAFIA FUERTE USANDO BORLAND DELPHI - Algunas palabras - Garantía - Definiciones - Advertencia - El algoritmo - El código 3. BARRA DE PROGRESO SIN MARCO 4. PUBLICACIONES ELECTRONICAS GRATUITAS 5. ENLACES ________________________________________________________________________ 1. UNAS PALABRAS DEL EDITOR El Sorteo de la Librería JfControls finalizó sin ganador, pero la gente de JfActiveSoft está determinada a regalar una licencia de todos modos, así que decidieron reducir el número de dígitos de la lotería a tres, y si nadie tiene el número que corresponde a los últimos tres dígitos del primer premio de la Lotería Nacional de España que tendrá lugar el Sábado 17 de Marzo, entonces se continuará con el segundo premio, tercero, cuarto, etc. hasta que haya un ganador. Esta vez tendrán más tiempo para inscribirse puesto que la fecha tope es el Jueves 15 de Marzo a las 20:00 GMT. Quienes se hayan inscripto para participar en el primer sorteo quedan automáticamente inscriptos para este nuevo sorteo y como cortesía recibirán un número adicional que les será notificado por email. Participar es gratis. Todo lo que tienen que hacer es descargar e instalar la versión de evaluación de la librería (disponible tanto para Delphi como para C++ Builder, ambos en versiones 3, 4 y 5) para así obtener el Key Number (un número único que identifica cada instalación de la librería) con el que podrán llenar el formulario de inscripción. Si no quieren instalar la versión de evaluación de la librería, la última versión de JfSetup le dará el Key Number si instala sólo la demo (vale la pena verla y no se requiere que la librería esté instalada para correr el ejecutable). Para más información sobre el sorteo: http://www.latiumsoftware.com/jfcontrols/index.php?lang=es En esta edición me complace presentar un artículo de Uri Fridman sobre criptografía, y también otro artículo de Vladimir S. mostrándonos cómo obtener una barra de progreso sin marco. Aprovecho para recordarles que este boletín sólo puede continuar con sus contribuciones. Si no tiene tiempo para escribir o si siente que no es bueno para eso, pero tiene algún código útil o interesante que quiera compartir con otros desarro- lladores, por favor contácteme y posiblemente yo pueda escribir algo por usted. Debe ser el autor del material que me envíe y sólo se aceptan contribuciones de código fuente... por favor no me envíen programas o unidades compiladas! Saludos, Ernesto De Spirito eds2004 @ latiumsoftware.com ________________________________________________________________________ JfControls Lib. Multilenguaje. Multiapariencia. Skins. Privilegios. Más de 40 componentes integrados y personalizables. Múltiples problemas de programación resueltos. Administración centralizada de recursos. Para Delphi 3-7 y C++ Builder 3-6. http://www.jfactivesoft.com/spindex.htm ________________________________________________________________________ 2. INTRODUCCION A LA PROGRAMACION DE CRIPTOGRAFIA FUERTE USANDO BORLAND DELPHI Copyright (c) 2001 Uri Fridman <urifrid@hushmail.com> Algunas palabras ================ Históricamente, la criptografía fue usada por los gobiernos a través de los tiempos para ocultar mensages secretos. La necesidad de mantener "secretos de estado" fuera del alcance del público en general llevó a la invención de varios métodos de encripción. En el Siglo XX estos métodos fueron llevados un paso más allá a medida que fueron automatizados por la introducción de máquinas como la Enigma (descifrada por los aliados en la 2da Guerra Mundial). Con la introducción de la computadora, este proceso automatizado se hizo aún más fácil e incluso se inventaron nuevos métodos criptográficos. Hoy las computadoras están en todos lados. Los gobiernos tienen acceso a casi todo. Los Administradores de Sistemas tienen acceso a todos los archivos de su disco duro. La competencia tiene acceso a laptops robadas... Quiero decir, tratando de no sonar "demasiado" paranoico, que en el mundo de hoy la privacidad se hace cada vez más difícil de lograr. Pero no se preocupen. Tenenos la Criptografía para ayudarnos. Garantía ======== SIN GARANTÍA. ESTE ARTICULO VIENE SIN NINGUNA GARANTIA, Y SE PROVEE SOBRE LA BASE "TAL Y COMO ESTA". USTED ASUME TODO EL COSTO DE CUALQUIER DAÑO RESULTANTE DE LA INFORMACION CONTENIDA EN O PRODUCIDA POR LOS CONTENIDOS DE ESTE ARTICULO. USTED ASUME TODAS LAS RESPONSABILIDADES POR LA SELECCION DE ESTE ARTICULO PARA LOGRAR SUS RESULTADOS ESPERADOS, Y POR LA INSTALACION DE, USO DE Y RESULTADOS OBTENIDOS DE EL. HASTA EL MAXIMO ALCANCE PERMITIDO POR LA LEY APLICABLE, URI, SUS PROVEEDORES Y OTROS QUE PUEDEN DISTRIBUIR ESTE ARTICULO DESCONOCEN TODA GARANTIA, YA SEA EXPRESA O IMPLICITA, INCLUYENDO PERO SIN LIMITARSE A LAS GARANTIAS IMPLICITAS DE COMERCIALIZACION, ADECUACION A UN PROPOSITO PARTICULAR, CONFORMACION CON LA DESCRIPCION, Y NO INFRINGIMIENTO, CON RESPECTO A ESTE PRODUCTO SOFTWARE. EN OTRAS PALABRAS: USELO BAJO SU PROPIO RIESGO Definiciones ============ En la terminología cripto, un archivo legible sin más se llama "Plaintext" (texto simple). El proceso de mezclar sus contenidos para hacerlo ilegible se llama Encripción, entonces estamos Encriptando un archivo. Este mensaje ilegible se llama ahora "Ciphertext" (texto cifrado). La operación inversa, desenmarañar el texto cifrado, se llama Desencripción, entonces Desencriptamos un archivo. Estos dos procesos usan una Llave ("Key") pata encriptar o desencriptar un archivo. Sólo conociendo la llave correcta deberíamos poder desen- criptar un mensaje encriptado con esa llave. Advertencia =========== Estas definiciones son todas buenas y lindas, pero el mundo real es un poco diferente. Puede parecer fácil y entretenido crear "ciphers" (algortimos criptográficos) pero no lo es. La buena encripción se ve igual que la mala. Ambas producen basura ilegible. Pero no se deje engañar. Siempre use ciphers públicos y bien conocidos, uno que haya sido estudiado por profesionales y haya sido analizado por años. Siempre trate de obtener el código fuente de los ciphers. Siga el siguiente enlace para aprender cómo diferenciar un buen producto de uno malo: http://www.interhack.net/people/cmcurtin/snake-oil-faq.html He tratado de ser tan preciso como sea posible al escribir este artículo. Sin embargo el español no es mi lengua natal y no soy un criptógrafo profesional, así que algunos errores pueden aparecer en el artículo. Por favor siéntase libre de comentarme acerca de ellos o de otros temas enviando un email a <urifrid@hushmail.com>. El algoritmo ============ Elegí Twofish como el algoritmo para esta introducción. Lo hice por varias razones: 1) Fue escrito por Bruce Schneier (www.counterpane.com), un criptógrafo y criptoanalista muy conocido 2) No ha sido roto 3) Es fácil de usar 4) ES PUBLICO. El código fuente puede obtenerse de varios lugares. 5) Puede uasrse en cualquier modo: ECB, CBC, CFB 8bit, OFB, OFB counter 8bit. Para conocer más acerca de los modos lea Applied Crytography (Criptografía Aplicada) de Bruce Schneier o vaya a su sitio web: http://www.counterpane.com En breve, Twofish es: - Un cipher de bloques de 128 bits. Encripta bloques de 128 bits de tamaño. - Llaves de 128, 192 o 256 bits. Puede usar varias longitudes para las llaves. En general, si un cipher tiene una llave de 128 bits se requerirían 2^128 intentos para tratar todas y cada una de las llaves. - Realiza 16 rondas de encripción. Itera el cipher 16 veces antes de devolver el texto cifrado. El código en Delphi para este algoritmo fue portado de la implementación original en C por David Barton (<davebarton@bigfoot.com>). Puede descargar muchos otros ciphers de su página web: http://www.scramdisk.clara.net Aquí proveo todos los archivos que se usan en este artículo. Los encontrará en el archivo que acompaña este artículo. El código ========= Cree un nuevo proyecto. Agregue 3 cuadros de texto (Edit1, Edit2 y Edit3), 4 buttons (encrypt, decrypt, hash and browse), también agregue un radiogroup y llámelo RadioHex, inserte dos radiobuttons en él, uno "Mostrar en Hexadecimal" y el otro "Mostrar en Base64". Vamos a agregar lo siguiente a la cláusula uses: uses SHA1, Twofish, Base64; * SHA1 es el Hash. Las funciones de hash de una sola vía son como huellas digitales de los datos "hasheados" que toman una entrada de longitud variable y producen una salida de longitud fija (160 bits en SHA1). Las funciones de hash aseguran que si la información se cambia de alguna forma —aunque sea por un solo bit— se produce un valor de salida completamente diferente. Esto es útil de muchas formas. Una de ellas es por ejemplo para encriptar un archivo y luego hacer un hash del archivo encriptado. Puede enviar tanto el archivo como su hash. Cuando el otro lado recibe el archivo puede verificar si el mismo ha sido alterando creando su hash y comparándolo con el hash que ha sido enviado. Por supuesto que el hash debe ser enviado de un modo que sea seguro que no sea tocado (probablemente usando algún algoritmo público de encriptación de llaves como RSA). Vamos a usar hashes para crear una huella digital tanto de la constraseña ingreada como del archivo encriptado. * TWOFISH es el algortimo de encripción. * Base64 es una forma de codificar la salida para que sólo esté formada por caracteres imprimibles. Agregue los siguientes procedimientos a su programa: // produce un hash de una cadena procedure _HashString(s: string; var Digest: TSHA1Digest); var Context: TSHA1Context; // registro para guardar los // datos intermedios begin SHA1Init(Context); // inicializa el reg. de datos SHA1Update(Context,@S[1],Length(S)); // actualiza el registro de // datos con la cadena SHA1Final(Context,Digest); // produce el hash final end; // produce un hash de un archivo procedure _HashFile(filename: string; var Digest: TSHA1Digest); var Context: TSHA1Context; // registro para guardar los // datos intermedios Source: file; // archivo origen Buffer: array[1..8192] of byte; // búfer de lectura Read: integer; // cantidad de bytes leídos begin AssignFile(Source,filename); try Reset(Source,1); except MessageDlg('No se pudo abrir el archivo de origen', mtInformation,[mbOK],0); Exit; end; SHA1Init(Context); // inicializa el reg. de datos repeat BlockRead(Source,Buffer,Sizeof(Buffer),Read); SHA1Update(Context,@Buffer,Read); // actualiza el hash until Read<> Sizeof(Buffer); SHA1Final(Context,Digest); // produce el hash final CloseFile(Source); end; Estos procedimientos producen un hash de una sola vía para archivos y cadenas. Note que el proceso de encripción y desencripción será como este: 1) obtener un hash de la contraseña 2) inicializar la llave en el algoritmo usando el hash 3) hacer un IV (el primer bloque a usar en los modos encadenados) 4) encriptar o desencriptar 5) quemar datos (llave en memoria, IV, etc.) y preparar el algoritmo para la siguiete tarea. 6) (Opcional) obtener un hash del archivo encriptado En (1) generamos el hash de la contraseña del usuario. Este hash será usado en (2) para inicializar la llave. Esta llave NO es la contraseña que el usuario escribió. En (3) generamos el primer bloque de datos encriptados, este bloque contiene datos aleatorios. Esto se hace porque estamos usando uno de los modos encadenados donde necesitamos que cada bloque dependa del anterior para ser encriptado. Esto ayuda a ocultar patrones en el texto como redundancias y otras cabeceras de archivo (como "PK" en archivos zipeados). En (4) realizamos la verdadera encripción/desencripción y en (5) nos deshacemos de los datos ubicados en memoria (no queremos ningún cracker robando nuestra contraseña ¿verdad?). Entonces, en el procedimiento OnClick del botón que llamamos Encrypt puede escribir lo siguiente (Advertencia, esto SOBRESCRIBIRA el archivo original. A menos que recuerde la constraseña, no podrá recuperar los datos): var KeyData: TTwofishData; // los datos de la llave inicializada Digest: TSHA1Digest; IV: array[0..15] of byte; // el vetor de inicialización vector // necesario para modos encadenados Buffer: array[0..8191] of byte; Source,source2: file; i, j, n: integer; Key: string; NumRead, NumWritten: Integer; begin Key:= edit2.Text; // you wrote the password in edit2 _HashString(Key,Digest); TwofishInit(KeyData,@Digest,Sizeof(Digest),nil); // inicializa los // datos de la llave usando el hash de la llave FillChar(IV,Sizeof(IV),0); // llenar al IV con ceros TwofishEncryptCBC(KeyData,@IV,@IV); // encriptar el IV para obtener // un IV 'aleatorio' Move(IV,KeyData.InitBlock,Sizeof(KeyData.InitBlock)); // mover el // IV en keydata para usar encadenamiento TwofishReset(KeyData); // resetear keydata para usar el nuevo IV AssignFile(Source, edit1.Text); // archivo a encriptar en edit1 try Reset(Source,1); except TwofishBurn(KeyData); // deshacernos de los datos MessageDlg('No se pudo abrir el archivo...', mtInformation, [mbOK], 0); Edit2.text:='00000000000000000000000000000000'; Edit2.text:=''; Exit; end; repeat n:= FilePos(Source); BlockRead(Source,Buffer,Sizeof(Buffer),i); for j:= 1 to (i div 16) do // 16 es el tamaño de bloque de // Twofish que procesa en bloques de bytes TwofishEncryptCBC(KeyData,@Buffer[(j-1)*Sizeof(IV)], // encriptar @Buffer[(j-1)*Sizeof(IV)]); if (i mod 16)<> 0 then // encrypt the last bytes that don't // fit in to a full block begin Move(KeyData.LastBlock,IV,Sizeof(IV)); TwofishEncryptCBC(KeyData,@IV,@IV); // encriptar el bloque // completo nuevamente (p/que esté encriptado dos veces) for j:= 1 to (i mod 16) do // xor this encrypted block with the short block Buffer[(i and not 15)+j]:= Buffer[(i and not 15)+j] xor IV[j]; end; Seek(Source,n); BlockWrite(Source,Buffer,i); // escribir el búfer en el archivo until i<> Sizeof(Buffer); CloseFile(Source); TwofishBurn(KeyData); // deshacernos de los datos Edit2.text:='00000000000000000000000000000000'; Edit2.text:=''; Edit1.text:=''; MessageDlg('Listo. El archivo ha sido encriptado con el mismo ' + 'nombre que el original.', mtInformation, [mbOK], 0); end; Presto! Acabamos de encriptar el archivo en Edit1 con la contraseña en Edit2! Para desencriptar hacemos exactamente lo mismo, pero en vez de usar TwofishEncryptCBC usamos: TwofishDecryptCBC(KeyData,@Buffer[(j-1)*Sizeof(IV)], @Buffer[(j-1)*Sizeof(IV)]); Simple, ¿no? Muy bien, tiene su archivo encriptado. Un lindo toque sería generar el hash de ese archivo encriptado y enviarlo junto con él. Para lograr esto usaremos el procedimiento _HashFile que escribimos antes. En el procedimiento OnClick para el botón que llamó Hash agregue lo siguiente: procedure TForm1.HashClick(Sender: TObject); var Digest: TSHA1Digest; // Forma binaria del hash i: integer; begin if Edit1.Text='' then exit; // asegurarnos que tenemos un archivo _HashFile(Edit1.Text,Digest); // calcular el hash y // guardarlo en Digest if radiohex.ItemIndex=0 then // queremos mostrar el // hash en hexadecimal begin Edit3.Text:= '0x'; for i:= 0 to (Sizeof(Digest)-1) do Edit3.Text:= Edit3.Text+IntToHex(Digest[i],2); // convertir Digest // a una cadena hexadecimal end else // in base64 begin Edit3.Text:= ''; for i:= 0 to (Sizeof(Digest)-1) do Edit3.Text:= Edit3.Text+chr(Digest[i]); // convertir Digest a // base64 Edit3.Text:=B64Encode(Edit3.Text); end; end; Ahora podemos elegir guardar el hash en un archivo y comprimir tanto el archivo encriptado como su hash en un solo arcihvo .zip. Podemos ahora enviar el archivo zip a un amigo estando seguros que sólo el/ella podrá desencriptarlo. Esta es una simple aplicación. Mucho más puede agregársele para hacerla más segura, pero este es sólo un ejemplo. Le queda a usted agregar su propio código y recuerde: "...que los fuentes lo acompañen." El código fuente de SHA1, Twofish y Base64 junto con el programa que los usa puede encontrarlo en el archivo que acompaña este artículo. Por favor asegúrese de leer la garantía muy cuidadosamente. Gracias. Uri, Febrero 10, 2001. - urifrid@hushmail.com --------------- NOTA: Por si tiene interés, Uri tiene una aplicación freeware que presenta una interfaz tipo explorador que le permite encriptar y desencriptar archivos. También hay disponible una versión de consola: http://www.geocities.com/urifrid/soft.html ________________________________________________________________________ 3. BARRA DE PROGRESO SIN MARCO Por Vladimir S. <shvetadvipa@mtu-net.ru> La barra de progreso (ProgressBar) de Delphi siempre tiene marco. Si desea ponerla en una barra de estado (StatusBar) no se ve muy lindo que digamos. Puede hacer un pequeño cambio en el componente y así obtener un nuevo componente sin borde. Vea la figura (progress.gif). Puede ver tres barras de progreso. Una es el componente estándar de Delphi con marco y el resto de ellas son el componente con una propiedad nueva. Ahora puede quitar el marco de la barra de progreso. unit NewProgress; // By Vladimir S. <shvetadvipa@mtu-net.ru> interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls; type TNProgressBar = class(TProgressBar) procedure WMNCPAINT(var Msg: TMessage); message WM_NCPAINT; private FShowFrame: boolean; procedure SetShowFrame(Value: boolean); public constructor Create(AOwner: TComponent); override; published property ShowFrame: boolean read FShowFrame write SetShowFrame; end; procedure Register; implementation { TNProgressBar } constructor TNProgressBar.Create(AOwner: TComponent); begin inherited; FShowFrame := True; end; procedure TNProgressBar.SetShowFrame(Value: boolean); begin if FShowFrame <> Value then begin FShowFrame:= Value; RecreateWnd; end; end; procedure TNProgressBar.WMNCPAINT(var Msg: TMessage); var DC: HDC; RC: TRect; begin if ShowFrame then begin inherited; Invalidate; end else begin DC := GetWindowDC(Handle); try Windows.GetClientRect(Handle, RC); with RC do begin Inc(Right, 2); Inc(Bottom, 2); end; Windows.FillRect(DC, RC, Brush.Handle); finally ReleaseDC(Handle, DC); end; end; end; procedure Register; begin RegisterComponents('Controls', [TNProgressBar]); end; end. ________________________________________________________________________ 4. PUBLICACIONES ELECTRONICAS GRATUITAS Para los programadores en Delphi de habla hispana existen hoy tres publicaciones electrónicas gratuitas: * AbracaDelphi! - Trucos Delphi en tu email Para estudiantes y principiantes en Delphi. Algoritmos, rutinas, ejercicios, etc. El primer número saldrá a fines de Febrero. Semanal. http://www.geocities.com/abracadelphi/ Suscribir: abracadelphi-subscribe@ecircle.es Cancelar : abracadelphi-unsubscribe@ecircle.es * Boletín Pascal - Una publicación gratuita para programadores Delphi (y Kylix) de nivel intermedio con artículos, trucos, noticias, enlaces... http://www.latiumsoftware.com/es/pascal/index.php Suscribir: pascal-es-suscribir@latiumsoftware.com Cancelar : pascal-es-cancelar@latiumsoftware.com * Revista Síntesis Una revista gratuita dedicada a todo lo referente al entorno Borland. Se recibe por email una notificación para descargar un archivo ZIP de la web (~1.3Mb) que contiene la revista en formato PDF y los ejemplos de código fuente dentro de otro ZIP. Bimensual. http://elrinconcito.com/grupoalbor/Sintesis/Sintesis.htm Suscribir: revista_sintesis-subscribe@egroups.com Cancelar : revista_sintesis-unsubscribe@egroups.com ________________________________________________________________________ 5. ENLACES * Lord Trancos' DirectX Laboratory (sitio en español) Recursos y código fuente sobre programación de DirectX 8 bajo Delphi http://www.geocities.com/dxlab/ ________________________________________________________________________ ¡TÚ PUEDES AYUDARNOS! Necesitamos tu ayuda para que este boletín pueda continuar y crecer. Una forma en que puedes ayudarnos es enviando este enlace a tus amigos: http://www.latiumsoftware.com/es/pascal/index.php Otra forma es votándonos en alguno de estos rankings para darle más visibilidad a nuestro sitio web y aumentar así el número de suscrip- ciones al boletín, que esperamos en el futuro se traduzca también en un mayor número de colaboraciones de artículos, trucos, etc.: http://www.sandbrooksoftware.com/cgi-bin/TopSite2/rankem.cgi?id=latium http://news.optimax.com/topdelphi/links.exe/click?id=70C517ECAE6E http://www.programmingpages.com/?r=latiumsoftwarecomenpascal http://www.top219.org/cgi-bin/vote.cgi?delphi&83 http://top100borland.com/in.php?who=20 http://top200.jazarsoft.com/delphi/rank.php3?id=latium http://213.65.224.200/cgi-bin/toplist.cgi/hits?Id=80 http://www.programacion.net/votar-enlace.php?id=474 http://www.lawebdelprogramador.com/buscar/enlace.php?id=615 Por favor vota. Son sólo unos segundos para ti que REALMENTE pueden hacer la diferencia. Necesitamos tu ayuda para poder continuar. ________________________________________________________________________ Si no has recibido el archivo con el código fuente completo de los ejemplos que se presentan en este boletín, puedes descargarlo de la siguiente dirección: http://www.latiumsoftware.com/descarga/p0017.zip ________________________________________________________________________ Página principal: http://www.latiumsoftware.com/es/pascal/index.php Página del grupo: http://espanol.groups.yahoo.com/group/boletin-pascal/ Para suscribirse / apuntarse: boletin-pascal-subscribe@gruposyahoo.com Para cancelar / removerse: boletin-pascal-unsubscribe@gruposyahoo.com Para reportar problemas con la suscripción: eds2004 @ latiumsoftware.com ________________________________________________________________________ Este boletín se provee "TAL Y COMO ESTA", sin garantía de ninguna clase. Su uso implica la aceptación de nuestros términos de licencia y de la ausencia de garantía que puedes leer en nuestro sitio web. Allí también encontrarás una nota sobre marcas registradas. Te animamos a que redis- tribuyas este boletín, siempre y cuando lo hagas en forma completa (incluyendo la información de copyright), sin modificaciones y de manera gratuita. Los artículos son copyright de sus respectivos autores y se reproducen aquí con el permiso de los mismos. ________________________________________________________________________ Latium Software http://www.latiumsoftware.com/es/index.php Copyright (c) 2001 por Ernesto De Spirito. Todos los derechos reservados ________________________________________________________________________ |
Los ejemplos completos de código fuente de este número están disponibles para descargar.

progress.gif
![]() |
¿Errores? ¿Omisiones? ¿Comentarios? Por favor contáctanos!






