Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Problemas al tratar de guardar y después recuperar una cadena de texto cifrada (https://www.clubdelphi.com/foros/showthread.php?t=85973)

dec 01-06-2014 22:33:32

Problemas al tratar de guardar y después recuperar una cadena de texto cifrada
 
1 Archivos Adjunto(s)
Hola a todos,

A ver si alguien puede echarme una mano con cierto problema que me he topado. Resulta que en uno de mis programas doy a los usuarios la posibilidad de cifrar y descrifrar cadenas y archivos. Tanto para cifrar y descifrar cadenas como archivos utilizo la misma clase, el mismo código, sin embargo, algo falla a la hora de cifrar cadenas.

Y aquí empieza el problema. En realidad el cifrado de cadenas no falla... pero, este programa que digo, se supone que tiene que retornar al usuario la cadena cifrada, es decir, para poder descifrarla después. Ahora bien, aunque estoy funciona... cómo decirlo... "en memoria", no funciona si se guarda la cadena cifrada en algún lugar.

¿Qué quiere decir algún lugar? Pues, por ejemplo, si ciframos una cadena y queremos mostrar la cadena cifrada en un "MessageBox", lo que este muestra es sólo una parte de dicha cadena cifrada, es como si se "perdiese" parte de la cadena, de manera que luego, claro está, es imposible descifrar dicha cadena y obtener el texto original.

Lo mismo ocurre si en lugar de mostrar la cadena en un "MessageBox" pretendemos copiarla en el portapapeles de Windows, mostrarla en un "TMemo", etc.: Lo que obtenemos es sólo una parte de la cadena cifrada, de manera que después lógicamente no hay forma de descifrarla. Ahora bien, si no mostramos o guardamos dicha cadena cifrada, entonces todo funciona como se espera.

Voy a tratar de explicarlo con un poco de código:

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
const
  SOURCE_STR = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
var
  cipher : TCipher;
  originalText, encryptedText, decryptedText : string;
begin
  originalText := DupeString(SOURCE_STR, 100) + ' #####';

  cipher := TCipher.Create();
  try
    encryptedText := cipher.EncryptString(originalText, 'password', haSHA512);

    decryptedText := cipher.DecryptString(encryptedText, 'password', haSHA512);

    ShowMessage(decryptedText);
  finally
    cipher.Free();
  end;
end;

Al ejecutarse el código anterior, el "ShowMessage" del final nos mostrará lo que esperamos: el texto original. Es decir, en el código anterior hemos cifrado una cadena, hemos descifrado la cadena previamente cifrada, y, mostrando esta última en el "ShowMessage" obtenemos el resultado esperado: una copia exacta de la cadena original.

¿Dónde está el problema entonces? El problema reside en que, como he dicho, de lo que se trata es de devolver la cadena cifrada al usuario, para que, digamos, el la guarde donde quiera, de manera que luego pueda descifrarla y obtener su cadena original. Pero esto no funciona.

De nuevo un poco de código:

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
const
  SOURCE_STR = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
var
  cipher : TCipher;
  originalText, encryptedText, decryptedText : string;
begin
  originalText := DupeString(SOURCE_STR, 100) + ' #####';

  cipher := TCipher.Create();
  try
    encryptedText := cipher.EncryptString(originalText, 'password', haSHA512);

    ShowMessage(encryptedText);

    decryptedText := cipher.DecryptString(encryptedText, 'password', haSHA512);

    ShowMessage(decryptedText);
  finally
    cipher.Free();
  end;
end;

El anterior código añade, justo después de cifrar la cadena, un nuevo "ShowMessage". Se supone que este "ShowMessage" debería mostrar la cadena cifrada, pero, no lo hace, es decir, lo que muestra es sólo parte de la cadena. Para que se entienda un poco mejor (o para intentarlo por mi parte, al menos) veamos el último trozo de código:

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
const
  SOURCE_STR = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
var
  cipher : TCipher;
  originalText, encryptedText, decryptedText : string;
begin
  originalText := DupeString(SOURCE_STR, 100) + ' #####';

  cipher := TCipher.Create();
  try
    encryptedText := cipher.EncryptString(originalText, 'password', haSHA512);

    Memo1.Text := encryptedText;

    decryptedText := cipher.DecryptString(Memo1.Text, 'password', haSHA512);

    ShowMessage(decryptedText);
  finally
    cipher.Free();
  end;
end;

En este último caso, en lugar de mostrar mediante un "ShowMessage" la cadena cifrada, la guardamos en un "TMemo". Así que después, tratamos de descifrar la cadena que acabamos de guardar en dicho "TMemo", sin embargo, no obtendremos el resultado deseado, puesto que el "TMemo" sólo contendrá/mostrará parte de la cadena cifrada, y, por tanto, será imposible obtener la original a partir de ella.

Estoy utilizando la cierta API de Windows que permite cifrar y descifrar archivos, todo ello encapsulado en una clase que ya publiqué hace tiempo aquí, basada en código del maestro Seoane. La adjunto en este hilo por si alguien quiere comprobar lo dicho. El caso es que dicha clase parece funcionar correctamente, puesto que, como se puede apreciar en el primer bloque de codigo mostrado, el cifrado y descifrado, tanto de cadenas como de archivos, se lleva a cabo perfectamente.

Pero claro, cuando ciframos y desciframos una cadena no mostramos la cadena cifrada, ni tampoco la guardamos en ningún otro lugar que no sea la variable correspondiente. Hecho esto así, como puede verse, todo funciona como se espera. Sin embargo, al tratar de guardar la cadena cifrada, para después y a partir de ella recuperar la cadena original parece tarea imposible.

¿Tendrá que ver con los caracteres, ciertamente "raros", que contiene una cadena cifrada? He probado a codificar esta cadena cifrada en "base 64", pero, tampoco he obtenido los resultados esperados. ¿A alguien se le ocurre alguna posible solución? ¿Alguien con experiencia en estos menesteres que sepa decirme cómo demonios salir de este lío en el que estoy metido?

Si ya has llegado leyendo hasta aquí, muchas gracias de antemano por tu posible ayuda. :)

Casimiro Noteví 01-06-2014 22:42:40

CREO que es porque obtienes caracteres inferiores al código 32 ascii y se pierden, por ejemplo el 7 haría un "beep" y se perdería, el cero corta la cadena por donde esté, etc.
Yo lo que hago, no sé si para bien o mal, pero funciona, es convertirlas a code64, así puedo mostrarla en cualquier mensaje, memo, etc.

dec 01-06-2014 22:58:07

Hola,

Gracias Casimiro. Que se "pierden" caracteres es evidente... aunque, ojo, sólo a la hora de guardar (o mostrarla en un "MessageBox", un "TMemo", etc.) la cadena cifrada: puesto que usando la variable que la contiene nosotros podemos descifrarla sin problemas. Ahora bien, he probado a convertir la cadena a "base 64" y el problema parece persistir. ¿Por qué digo parece? Porque he estado tan liado con esto que ahora mismo no sé si hice bien la prueba con "base 64". Mañana lo intentaré de nuevo. Sin embargo ahora mismo juraría que no es solución: que dichos caracteres se pierden también al tratar de convertir la cadena cifrada a "base 64", es decir, "faltan" cuando se decodifica la cadena (desde "base 64") y trata uno de descifrarla.

De todas formas, tal vez exista algún otro tipo de codificación posible en lugar de "base 64". Me explico. El debugger de Delphi me muestra el contenido de la cadena cifrada, pero, no reconozco dicho contenido como el que se guarda al cifrar un archivo (usando la misma clase) o una cadena, es decir, ¿podría Delphi estar codificando dicha cadena para mostrarla en el debugger? ¿Y qué codificación usaría? Ahora bien, esto tal vez no sirva de nada... pues seguramente Delphi no usará el contenido de la cadena que me muestra a mí en el debugger... sino que usará la propia variable que contenga la cadena cifrada. Espero que se entienda lo que quiero decir.

Pero sí... tal vez se trata de codificar dicha cadena cifrada de forma que no se pierdan los caracteres...

Gracias de nuevo Casimiro. Se agradece cualquier tipo de ayuda con este asunto, porque, en efecto, tengo que "presentar" alguna solución. :o

dec 01-06-2014 23:39:06

Hola de nuevo,

Curiosamente, aquí se describe exactamente (si no me equivoco) el problema que tengo. Y la solución propuesta pasa por codificar en "base 64" la cadena cifrada... ¿lo habré hecho yo entonces mal en mis anteriores pruebas? Mañana volveré a comprobarlo y veremos. Por favor recordad que cualquier tipo de ayuda sigue siendo bienvenida.

dec 02-06-2014 01:05:45

Hola,

Tal vez esta tarde he metido la pata al probar codificando la cadena cifrada en "base 64": he probado de nuevo y he podido comprobar que, en efecto, codificar la cadena cifrada tal vez sea una solución. No sé si lo será para mi problema en concreto, puesto que no puedo probarlo todavía en el programa en cuestión, pero, en un programa de prueba que estoy haciendo aquí, en efecto, algo así funciona como se espera:

Código Delphi [-]
uses
  StrUtils, IdCoderMIME, UCipher;

function Encode(str : string) : string;
var
  encoder : TIdEncoderMIME;
begin
  encoder := TIdEncoderMIME.Create();
  try
    result := encoder.Encode(str);
  finally
    encoder.Free();
  end;
end;

function Decode(str : string) : string;
var
  decoder : TIdDecoderMIME;
begin
  decoder := TIdDecoderMIME.Create();
  try
    result := decoder.DecodeString(str);
  finally
    decoder.Free();
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
const
  SAMPLE_TEXT = 'Hello dolly how are you I am fine ok goodbye. ';
var
  cipher : TCipher;
  encryptedText : string;
begin
  cipher := TCipher.Create();
  try
    encryptedText := cipher.EncryptString(DupeString(SAMPLE_TEXT, 150), 'password', haSHA512);

    Memo1.Text := Encode(encryptedText);

    ShowMessage(cipher.DecryptString(Decode(Memo1.Text), 'password', haSHA512));
  finally
    cipher.Free();
  end;
end;

Como puede verse estamos guardando la cadena cifrada en el "TMemo", no obstante, lo hacemos codificándola en "base 64". Pues bien, después de descodificarla de nuevo podemos descifrarla obteniendo como resultado la cadena original. Mañana comentaré si al final consigo que esto también funcione donde lo necesito.

P.D. Gracias Casimiro por hacerme mirar esto más despacio. ;)

Casimiro Noteví 02-06-2014 10:02:40

Ya sabes, "vísteme despacio que tengo prisa" :)

dec 02-06-2014 11:59:17

Hola,

Es verdad Casimiro. Y, sin embargo... el problema no se ha solucionado. No sé porqué, el programa de pruebas en Delphi 2007 bajo Windows 7, produce los resultados esperados. Sin embargo, este mismo programa en Delphi 2007 bajo Windows 8... no produce los resultados que esperamos. Parece algo relacionado con la codificación y decodificación en "base 64". Creía haber dado con la solución y ahora me encuentro con un problema caso más raro... :(

Casimiro Noteví 02-06-2014 12:07:43

Eso no tiene mucha lógica, code64 no puede variar (no debería) si usas win7 o win8 :confused:
¿No habrá algo más que sea diferente entre ambos equipos?

dec 02-06-2014 13:33:25

Hola,

Gracias Casimiro. Ahora mismo acabo de probar un ejecutable compilado en Delphi 2007 en Windows 7 y funciona como se espera también en Windows 8. Sin embargo, si compilo el código que produce dicho ejecutable en Delphi 2007 bajo Windows 8 el resultado no es el esperado. Algo falla. Lo único que se me ocurre ahora mismo es que la versión de los componentes Indy (usados para codificar/decodificar) es distinta, puesto que en Windows 7 uso la que viene instalada en Delphi 2007, y, casi estoy seguro, aquí en Windows 8, tengo instalada la última versión de Indy.

Pareciera en efecto que se trata de un problema en la codificación/decodificación, así que voy a intentar (también vaya día tengo hoy...) usar otros componentes para codificar/decodificar, aquí mismo en el ClubDelphi se han compartido algunas funciones para hacerlo. Claro que como tú dices, Casimiro, a mí también me extraña mucho que la codificación/decodificación no coincida entre diferentes versiones de Indy.

Y, por otro lado, si esto fuese así, resultaría que el problema está en la última versión de los componentes... Madre mía...

dec 02-06-2014 13:54:33

Hola,

Bueno, pues, seguimos avanzando (?). En efecto, probando a codificar y decodificar usando esta unidad, en lugar de los componentes Indy, todo parece funcionar correctamente en Delphi 2007... tanto en Windows 7 como en Windows 8.

¿Todo arreglado entonces? Realmente, no. Personalmente, hago uso de los componentes Indy para codificar y decodificar en "base 64" en varios de mis proyectos. Y hasta ahora todo parecía funcionar bien. De hecho acabo de hacer una prueba en cierto programa y funciona bien...

¿Qué me pasa doctor?

Casimiro Noteví 02-06-2014 14:09:58

Estos problemitas son los más complicados de resolver, necesitan mucha investigación detectivesca :rolleyes:

dec 02-06-2014 14:27:19

Hola,

Sí; desde luego, no sé yo si tendré tiempo y lugar como para ponerme a investigar qué puede estar pasando en definitiva. Más bien tal vez sea mejor esperar a que algo falle para tratar de arreglarlo. A mí me extraña mucho que la última versión de Indy añada algún "bug" que no existía en versiones anteriores, pero, lo cierto es que sería posible. Pero me extraña doblemente, porque, para mí tengo que Indy se usa profusamente en muchos proyectos, de manera que parece raro que un error así no está arreglado o no se comente por ahí... ahora que lo pienso, tal vez pueda buscar información sobre esto: a ver si se comenta por ahí o no sobre algún error en la última versión de Indy en relación a al componente para trabajar con "base 64"... ya veremos.

roman 02-06-2014 18:40:05

Una pregunta: ¿por qué tienes que codificar en base 64? Eso sólo es para cuando necesitas transmitir la información en formato sólo texto, por ejemplo, cuando envías un correo electrónico, pero de otra forma es innecesario. Claro que no podrás mostrarla en un TMemo pero de todas maneras, ¿qué haría el usuario con esa información encriptada en el Memo? Si simplemente necesitas que el usuario conserve esa información puedes guardarla en un archivo usando un stream.

// Saludos

escafandra 02-06-2014 19:25:07

Habría que mirar ese código despacito y como se realizan ciertos cast. No es muy buena idea mezclar string con buffers cifrados pues éstos, además de caracteres no imprimibles pueden contener "ceros" en el buffer cifrado, al convertirlo a string la cadena se parte en en "0". Recordar el estilo "C" de cadenas ASCIIZ. Es probable que te esté ocurriendo esto. No que no tiene ninguna lógica es que no te funcione con BASE64, que está pensado para evitar este efecto.


Saludos.

roman 02-06-2014 19:33:50

Los strings pueden manejar perfectamente bytes no imprimibles incluido el cero. Lo único que no puedes es, este, imprimirlos. Por eso, insisto, a menos que quiera mostralo en un Memo, mandarlo por correo, guardarlo en un XML o algo por el estilo, no tiene necesidad de pasar a base 64.

// Saludos

escafandra 02-06-2014 20:42:26

Claro, roman, por eso me he referido al cast de conversión PBYTE -> String en el que se va a partir la cadena en cuanto encuentre un #0. Pero ya digo, hay que revisar el código al usar la API de windows y su conversión a String. Naturalmente puedo estar equivocado (no revisé el código), pero el hecho de que se parta la cadena me hace pensar en esa posible causa.


Saludos.

escafandra 02-06-2014 21:03:25

Acabo de probar el código y funciona bien. El primer ShowMessage no muestra toda la cadena cifrada porque realiza una conversión a PCHAR en el seno de ShowMessage. He realizado un debug hasta llegar al punto del fallo, en concreto cuando usa la API DrawText y corta en el primer #0 encontrado. El problema no es del cifrado sino de ShowMessage de delphi. En caso de usar cualquier otra API que use cadenas, el efecto será similar.


Saludos.

roman 02-06-2014 21:04:48

Quizá me confundo pero yo a lo que me refiero es al código original que pone dec antes de entrar a lo de convertir a base 64.

Él dice que en este código

Código Delphi [-]
 encryptedText := cipher.EncryptString(originalText, 'password', haSHA512);

Memo1.Text := encryptedText;

decryptedText := cipher.DecryptString(Memo1.Text, 'password', haSHA512);

ShowMessage(decryptedText);

Cita:

Empezado por dec
En este último caso, en lugar de mostrar mediante un "ShowMessage" la cadena cifrada, la guardamos en un "TMemo". Así que después, tratamos de descifrar la cadena que acabamos de guardar en dicho "TMemo", sin embargo, no obtendremos el resultado deseado, puesto que el "TMemo" sólo contendrá/mostrará parte de la cadena cifrada, y, por tanto, será imposible obtener la original a partir de ella.

Y, claro, es imposible que obtenga el resultado original porque un Memo no maneja strings con bytes no imprimibles. Pero eso no quiere decir que no pueda guardar el resultado y recuperarlo posteriormente.

Por ejemplo, puede meter encryptedText en un TStringStream, copiar el stream a un TFileStream y guardarlo a disco. Siguiendo los pasos inversos necesariamente obtendrá el texto original.

// Saludos

roman 02-06-2014 21:06:10

Cita:

Empezado por escafandra (Mensaje 477174)
Acabo de probar el código y funciona bien. El primer ShowMessage no muestra toda la cadena cifrada porque realiza una conversión a PCHAR en el seno de ShowMessage. He realizado un debug hasta llegar al punto del fallo, en concreto cuando usa la API DrawText y corta en el primer #0 encontrado. El problema no es del cifrado sino de ShowMessage de delphi. En caso de usar cualquier otra API que use cadenas, el efecto será similar.


Saludos.

Contesté mientras escribías tú. Éso es a lo que me refiero. Ni el Memo ni el ShowMessage lo van a hacer correctamente (porque sólo trabajan con texto imprimible). La rutina de seoane está perfecta.

// Saludos

escafandra 02-06-2014 21:09:53

Cita:

Empezado por roman (Mensaje 477176)
Contesté mientras escribías tú. Éso es a lo que me refiero. Ni el Memo ni el ShowMessage lo van a hacer correctamente (porque sólo trabajan con texto imprimible). La rutina de seoane está perfecta.

Claro que está perfecta, el error no está en caracteres no imprimibles pues se escribirá cualquier cosa, el error está en el primer cero que aparezca al usar la API, en este caso DrawText. :)

Saludos.

dec 02-06-2014 21:10:21

Hola a todos,

Gracias por vuestro interés. Román, no se trata de mostrar la cadena cifrada en un "Memo", pero, de guardarla en un archivo INI, por ejemplo (por esto saltó la liebre, como suele decirse). O, en todo caso, se trata de "retornar" una cadena cifrada, que, después debería poder descifrarse para obtener la cadena original. De todas formas me has dejado una duda que quiero probar... Lo cierto es que todavía estoy con la mosca detrás de la oreja, fundamentalmente, por estos dos motivos:

1º Todavía no me explico cómo es posible que el mismo código que funciona en Delphi 2007 bajo Windows 7 no lo hace de igual modo en Delphi 2007 bajo Windows 8. Pero, en fin, vamos a dar por hecho algún tipo de error introducido en las últimas versiones de Indy, cosa que me extraña muchísimo, pero, puesto que el problema "parece" solucionarse usando un componente distinto de Indy, de acuerdo, sigamos adelante... pero...

2º Resulta que de este modo, con el nuevo componente (no Indy) todo va sobre ruedas en Delphi, esto es, puedo cifrar y descifrar cadenas verdaderamente largas sin problema alguno. Pero... por alguna razón, cuando lo pruebo en mi programa, no es que no funcione, pero, es que puede cifrar cadenas de (ojo al dato) hasta 60.000 caracteres. Como lo leéis. A mí me suena que esa es la cifra máxima permitida para una "línea"...

Bien. Quisiera ahora hablar un poco de mi programa, sólo para declarar su naturaleza un tanto "especial". Mi programa es en realidad una DLL, que a su vez será usada por otro programa. ¿Complica esto las cosas? Bueno, sí, pero no. Llevo hechas ya varias decenas de DLL para dicho programa "host", y, ciertamente, a veces he notado comportamientos extraños que no notaba en Delphi. Resumiendo, esto podría deberse a las características del programa, de trabajar desde una DLL, etc.

Pero el caso es que me llama muchísimo la atención no poder cifrar cadenas de más de una cifra tan redonda como 60.000 caracteres... me parece una cifra demasiado redonda como para que no signifique algo. ¿Cuál es mi problema ahora, por lo tanto? Pues que, asumiendo que usar "base 64" sea la solución, lo cierto es que esta solución funciona sin problemas en un programa de pruebas hecho en Delphi, pero, no en la DLL desarrollo y a su vez utiliza otro programa.

Voy a intentar que el autor de dicho programa me eche una mano, en el sentido de si a él le sonase de algo una cifra mágica como es 60.000 caracteres... ni uno más. Por supuesto si se os ocurre cualquier cosa al respecto os estaría muy agradecido.

P.D. Román, de hecho la DLL que desarrollo cuenta con "acciones" para cifrar y descifrar cadenas y archivos. Ahora bien, en lo tocante a archivos no he tenido problemas en cifrar y descifrar archivos de cualquier tamaño y tipo. Pero claro,... las acciones para cifrar cadenas se supone que deberían servir también. Ay diosito mío. :o

escafandra 02-06-2014 21:13:48

Cita:

Empezado por dec (Mensaje 477178)
1º Todavía no me explico cómo es posible que el mismo código que funciona en Delphi 2007 bajo Windows 7 no lo hace de igual modo en Delphi 2007 bajo Windows 8. Pero, en fin, vamos a dar por hecho algún tipo de error introducido en las últimas versiones de Indy, cosa que me extraña muchísimo, pero, puesto que el problema "parece" solucionarse usando un componente distinto de Indy, de acuerdo, sigamos adelante... pero...

Yo lo he probado en Win8, pero compilado con delphi7 y el error en ShowMessage es el esperado.

No trates de guardarlo en un archivo de texto (INI) pues obtendrás el mismo error, usa un archivo binario.


Saludos.

roman 02-06-2014 21:15:40

Si quieres guardar el resultado en un archivo INI, desde luego, no tienes otra opción que hacer una conversión a base 64 o similar. Pero, puedes guardarlo en un archivo binario y olvidarte del base 64 :)

// Saludos

roman 02-06-2014 21:16:07

Je, je, nos vamos pisando los talones :)

// Saludos

escafandra 02-06-2014 21:16:38

Sip. :)

Saludos.

dec 02-06-2014 21:25:13

Hola,

Gracias por responder. Entiendo lo que queréis decir, y, si de mí dependiera, esa sería probablemente la solución que tomase. Tal vez algo falla en la lógica del producto que ofrezco, lo que también me gustaría que se me dijese si es así. Bien. El caso es que yo ofrezco una DLL que añade "acciones" a un programa "madre" o "host". Para simplificar diremos que estas acciones son: cifrar cadena, descifrar cadena, cifrar archivo, descifrar archivo.

Ahora bien, si se ofrece la acción "cifrar cadena", para mí es obvio (¡pero puedo estar completamente equivocado!) que tenemos que retornar al usuario de nuestra DLL la cadena cifrada. Dónde la guarde o lo que haga con ella no es de nuestra incumbencia. Lo que pasa es que, dicho así, podría uno replicar: "Un momento, si el usuario necesita pasar la cadena cifrada a base 64, ¡que lo haga el mismo!".

Pero es que el problema reside en que, sea por las características de la comunicación entre DLL y programa "madre", la cadena cifrada no llega, directamente, a retornarse al usuario. Queda truncada. De manera que no es posible después su descifrado. Ahora bien... os juro por dios que ahora mismo dudo de si hasta he probado esto efectivamente... esto es, si la cadena se descifra aunque sea "en memoria", es decir, sin guardarla en sitio alguno.

Así que no me queda otra que volver a hacer pruebas de nuevo. Como decía Casimiro, vísteme despacio que tengo prisa... Aunque de todos modos, por favor, prestad atención a lo dicho en el primer párrafo, en el sentido de que no se trata de lo que yo haga con la cadena cifrada (y mi empeño verla en un "Memo" o lo que sea) sino que es el usuario de mi DLL quien debe recibir una cadena cifrada que después pueda descifrar.

Gracias de nuevo por vuestro interés.

P.D. Quisiera recordar la cifra mágica de 60.000 ¿caracteres? como posible límite de algún tipo en algún lugar...

roman 02-06-2014 21:31:04

Claro, tú le entregas la cadena al usuario y él hará lo que mejor le convenga, incluso pasarla a base 64 :p. Pero, ¿quién te obliga a entregársela através de un Memo?. Ponle un botón que diga: "Guarde esta cadena donde a usted más le quep, digo, convenga" :D

// Saludos

dec 02-06-2014 21:38:53

Hola,

Román, acabo de probar de nuevo como si no hubiésemos hablado nada, es decir, quitando del medio la codificación/decodificación en "base 64". En este caso no he tratado de mostrar la cadena en un Memo, pero, he querido guardarla en un archivo. Pero estamos en las mismas: la cadena que la DLL pasa al programa, por un motivo que desconozco, parece perderse en parte por el camino...

Sin embargo creo (estoy medio loco ya) comprender el asunto que tratáis de explicarme. Es decir, si yo cifro una cadena en Delphi y trato de guardarla en un archivo, estaré en la misma situación, de ahí que vosotros me sugiráis guardar la cadena en un archivo binario. De hecho acabo de probar a guardar la cadena recién cifrada en un "TStrings", y, de ahí a un archivo, y, en efecto, el problema es el mismo...

Ciertamente, comienzo a pensar que tal vez esto requiera de un planteamiento diferente. ¡Pero no tengo ni idea ahora mismo de cuál puede ser! :(

Si uno quiere hacer un programa cifrador/descifrador de cadenas... ¿cómo se supone que debe entregar la cadena cifrada al usuario para que este pueda guardarla donde más le plazca? ¿No podrá? ¿Entonces para qué demonios sirve el cifrador/descifrador? ¿Qué es lo que no estoy entendiendo bien?

roman 02-06-2014 21:41:58

Un TStrings tampoco te sirve, es lo mismo que un TMemo a final de cuentas. Son clases pensadas para mostrar texto y cualquier información binaria se pierde. Usa streams.

// Saludos

dec 02-06-2014 21:44:43

Hola a todos,

Cita:

Empezado por roman (Mensaje 477194)
Un TStrings tampoco te sirve, es lo mismo que un TMemo a final de cuentas. Son clases pensadas para mostrar texto y cualquier información binaria se pierde. Usa streams.

// Saludos

Quizá aquí deba decirse que el programa "madre" o "host" en cuestión (no mi DLL, claro está) no conoce de tipos "stream". Sólo trabaja con enteros y cadenas. También algún tipo de "array", pero, no sabe lo que es un "stream" y por tanto no puedo "pasar" un "stream" como acaso sería lo suyo.

¿Nos vamos acercando?

roman 02-06-2014 21:47:58

¡Ah! Caray. Pues, ¿que no estamos hablando de delphi? Si está en Object Pascal debe haber streams, o ¿qué no estoy entendiendo?

Por otro lado, no sé en los delphis actuales, pero en los antiguos no puedes pasar un string de dll a aplicación ni viceversa. Pero eso no debería ser problema. Conviertes a PChar antes de entregarla al programa host.

// Saludos

dec 02-06-2014 21:55:51

Hola,

En efecto, el programa está hecho en Delphi (desde los tiempos de Turbo Pascal, si no me equivo) y es un programa estupendo: NeoBook. Este programa, en pocas palabras, es un IDE para "no programadores". Permite crear aplicaciones para Windows de una forma "visual" y muy sencilla, seleccionado las "acciones" que uno quiere llevar a cabo: leer un archivo, escribir un archivo, hacer una petición HTTP, cifrar cadenas...

El programa, es decir, el propio NeoBook, sí que entiende de "streams", por supuesto, pero, no los programas generados con NeoBook. Este NeoBook es el IDE y también el intérprete de las acciones que el usuario programe. Y dicho usuario cuenta con la posibilidad de usar variables simples (cadenas, numéricas) o definir algunos tipos de variables más avanzadas como "arrays", pero, no el tipo "stream" o alguno similar.

Además, en efecto, la DLL trabaja con PChar. Es el propio NeoBook el que, en su SDK (Software Development Kit), ofrece ciertas funciones para establecer "variables de NeoBook", obtener su valor, etc. Me quedo con el hecho claro de que las aplicaciones desarrolladas con NeoBook no soportan el tipo "stream", y tal vez por aquí deberíamos empezar a obtener una explicación a todo lo que está pasando, en lugar de tratar de codificar la cadena cifrada en "base 64".

Ahora bien, tal vez, por la propia naturaleza de NeoBook (esto se podría explicar así a los usuarios de mi DLL) el plugin necesariamente tenga que hacer esa codificación en "base 64", puesto que no es posible retornar la cadena cifrada tal cual en una cadena de texto. Pero superado este razonamiento que parece lógico y entendible, nos encontraríamos con la cifra mágica de 60.000 caracteres... es decir, en Delphi puedo cifrar y codificar en "base 64" cadenas de muchos más caracteres.

Y aquí estamos hablando de cadenas de texto... ¿por qué demonios, entonces, no podría la DLL hacer lo mismo que el programa de pruebas de Delphi (de hecho usan el mismo código) y enviar la cadena a NeoBook, tenga esta la longitud que tenga? Más aún, ¿por qué se corta inexplicablemente a los 60.000 caracteres exactos? Vale decir que he probado a enviar cadenas de este tamaño (pero sin codificar ni nada) y NeoBook parece recibirlas correctamente.

escafandra 02-06-2014 21:57:06

Puedes pasar la cadena cifrada a una cadena hexadecimal, en ese caso tendrás siempre texto puro y tu cliente podrá hacer lo que quiera con esa cadena, siempre y cuando la convierta a binario antes de descifrarla.

Saludos.

dec 02-06-2014 22:06:59

Hola a todos,

Cita:

Empezado por escafandra (Mensaje 477199)
Puedes pasar la cadena cifrada a una cadena hexadecimal, en ese caso tendrás siempre texto puro y tu cliente podrá hacer lo que quiera con esa cadena, siempre y cuando la convierta a binario antes de descifrarla.

Saludos.

Gracias escafandra. No sé si querrás decir que puede usarse otra cosa que no sea "base 64". En efecto, yo también lo he pensado, aunque, no había pensado en la solución que tú propones. De hecho podría ser una solución (si funciona), puesto que, digo yo, el usuario podrá pasarme esa cadena... y ser yo el encargado de convertirla a otra cosa. Pero no creas que tengo claro ahora mismo cómo hacerlo...

Por cierto, acabo de comprobar que, en efecto, una DLL puede pasar a NeoBook cadenas de mucho mayor tamaño que 60.000 caracteres. He cargado un archivo de texto mucho mayor en un "TStrings", lo he asignado a una variable de NeoBook (tal como se hace con la cadena codificada en "base 64") y la aplicación de NeoBook recibe dicha variable y puede a su vez guardarla en un archivo sin pérdidas de ningún tipo.

¿Qué está pasando aquí? :rolleyes:

escafandra 02-06-2014 22:10:50

Pasa a tu dll un buffer y su tamaño, es decir, un puntero al primer elemento de tu String y su tamaño, de esa forma probablemente no tendrás errores.


Saludos.

dec 02-06-2014 22:14:26

Hola,

Cita:

Empezado por escafandra (Mensaje 477201)
Pasa a tu dll un buffer y su tamaño, es decir, un puntero al primer elemento de tu String y su tamaño, de esa forma probablemente no tendrás errores.


Saludos.

No estoy seguro de que algo así pueda funcionar escafandra. Recordemos que el usuario sólo puede pasar a mi DLL una cadena de texto, no un "buffer" ni nada parecido. ¿O lo he entendido mal?

Por cierto que ya vamos acotando el asunto... he guardado en un archivo de texto unos 80.000 caracteres codificados en "base 64". Desde mi DLL leo dicho archivo (usando "TStrings") y asigno su contenido a una variable de NeoBook.

Pues bien, dicha variable se asigna correctamente... y la aplicación puede guardar su contenido a otro archivo de texto sin que se pierda nada en absoluto. Y ahora es cuando digo que creo haber acotado algo que no sé ni lo que es... v\||/

escafandra 02-06-2014 22:23:59

En realidad un String no es otra cosa que un buffer y un tamaño...

Debes tener claro si quieres base64 u otra cosa. Cualquier otra cosa binaria puedes pasarla a su texto en hexadecimal... tu decides :)

Saludos

dec 02-06-2014 22:39:31

Hola,

Cita:

Empezado por escafandra (Mensaje 477204)
En realidad un String no es otra cosa que un buffer y un tamaño...

Debes tener claro si quieres base64 u otra cosa. Cualquier otra cosa binaria puedes pasarla a su texto en hexadecimal... tu decides :)

Saludos

Gracias escafandra. Te juro que no sé cómo hacer lo que me sugieres. Otrosí recordemos que yo recibo variables del tipo PChar y no de tipo String. No sé si esto implica algo.

Por lo demás, si os cuento lo que acabo de hacer no lo creéis. Como he dicho arriba, otra de mis DLL permite al usuario codificar y decodificar en "base 64". Ahora bien, esta DLL usa los componentes Indy para llevarlo a cabo.

Pues bien, he probado a codificar un archivo de texto en "base 64" con una de estas acciones, es decir, enviar al programa "madre" la cadena codificada (no cifrada) en "base 64", y, ¿y qué diréis que ha pasado? Exacto: no puedo enviar más de 60.000 caracteres exactos.

O sea, suponiendo que algún usuario de dicha DLL quisiera codificar más de 60.000 caracteres se encontraría con el problema de no poder hacerlo... por si tenía poco con un problema, ahora acaso tengo dos. ¡Toma ya!

¿Pero qué demonios significa esta limitación de 60.000 caracteres? ¿Por qué, exactamente, 60.000 caracteres? ¿Cómo es que dicha limitación existe si se usa Indy como si se usa la unidad que he enlazado más arriba?

Uff... :confused:

Casimiro Noteví 02-06-2014 22:47:36

Puede que esos 60000 caracteres, en su día, surgió de una manera similar a: ¿quién va a necesitar más de 640 Kb? :D

roman 02-06-2014 22:57:47

Además siempre puede poner la leyenda:

"Debido a limitaciones propias de NeoBook, este plugn sólo puede cifrar un máximo de 60,000 caracteres"

Supongo que también puedes partir en pedazos de 60000 o menos y pasar pieza por pieza.

// Saludos


La franja horaria es GMT +2. Ahora son las 03:30:35.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi