| Encriptando código |
¿Estoy buscando el nirvana?
Hace algunos días un amable comunicante me planteó una duda metafísica -que me produjo un cierto sonrojo- al preguntarme sobre la utilidad de los operadores bit a bit que tengo comentados en estas «Memorias» y me lanzó el guante de intentar ejemplificarlos con alguna aplicación práctica.Un primer intento fallido
Aquí a la derecha tienes los scripts de un primer intento... que resultó -como era de esperar- fallido.Una tabla de números aleatorios
Crear una tabla de números aleatorios no era excesivo problema... pero tenía un par de dudas muy importantes:El proceso de encriptación
En este segundo intento lo único que hice modificar el script anterior.El proceso de desencriptación
La desencriptación no me planteó ningún problema.El tercer intento
En un principio pensé que la solución sería fácil. Pensaba que bastaría guardar la salida del script de descodificación en fichero y pensé que el directorio temporal del servidor podría ser un buen sitio por aquello de su condición de temporalidad... pero... una cosa piensa el borracho... y otra muy distinta el tabernero... y ocurrió que no había contado con que la configuración del PHP en mi servidor safe mode=on me impedía escribir en ese directorio.¿Cómo puedo ser tan bruto?
Pues... si... tengo la sensación de mis orejas miden algo así como metro y medio... Señor, Señor... llevo una diciéndome a mí mismi: «yes un pollinín» (algo así como eres un burro, pero ... en bable y cariñosamente ;-)Dificultando la lectura del código fuente
Tal como comento al margen, entiendo que la encriptación de los scripts de PHP puede tener justificación en el sentido de proteger aplicaciones de accesos malintencionados, pero no comparto la idea de ocultar el código fuente de las páginas que se envían al navegador del cliente.
Invirtiendo bits... primer intento
<? $fichero="index1.php"; # bufferizamos la salida para que no sea visible # en el navegador del cliente ob_start(); # abrimos el fichero en a "encriptar" # en modo "lectura" $f1=fopen($fichero,"rb"); # leemos el contenido integro del fichero fpassthru($f1); # recogemos el contenido del buffer # en la variable cadena $cadena = ob_get_contents(); # acabamos la bufferización # y borramos el buffer ob_end_clean(); # invertimos los "bits" de cada # uno de los caracteres de la cadena # que contiene el fichero original $cd=~$cadena ; # guardamos la cadena invertida # en un nuevo fichero... que sería el fichero "encriptado" $f1=fopen("index1_cd.php","w"); fwrite($f1,$cd); fclose($f1); ?>
<? $fichero="index1_cd.php"; # bufferizamos la salida para que no sea visible # en el navegador del cliente ob_start(); # abrimos el fichero en a "desencriptar" # en modo "lectura" $f1=fopen($fichero,"rb"); # leemos el contenido integro del fichero fpassthru($f1); # recogemos el contenido del buffer # en la variable cadena $cadena = ob_get_contents(); # acabamos la bufferización # y borramos el buffer ob_end_clean(); # invertimos los "bits" de cada # uno de los caracteres de la cadena # que contiene el fichero encriptado # y que harían la desencriptación $cd=~$cadena ; y enviaríamos la cadena desencriptada a navegador echo $cd; ?>
Complicando la codificación
Se trataba de conseguir que la inversión de bits no fuera lineal (aplicada sin más a todos y cada uno de los caracteres del fichero) sino que se produjera de forma aleatoria a lo largo del documento, de manera que unos bits aparecieran invertidos en el documento encriptado y otros aparecieran tal cual para eso... pensé que lo mejor sería... crear una tabla de números aleatorios.
<?
for($i=1;$i<10000;$i++){
$v=mt_srand((double)microtime()*1000000);
$matriz[$i]=mt_rand(1,10000);
}
sort($matriz);
$f1=fopen("claves_beta","a");
foreach($matriz as $c){
fwrite($f1,$c."\r\n");
}
fclose($f1);
?>
<? # incio la buferización ob_start(); # abro el fichero "a encriptar" # en modo lectura $f1=fopen("index1.php","r"); # escribo el contenido # en el buffer de salida fpassthru($f1); # recojo el buffer el # la variable cadena $cadena = ob_get_contents(); # cierro el buffer y lo borro ob_end_clean(); # invierto todos los bits de la cadena # que contiene el fichero "a encriptar" $cd=~$cadena ; # inicio una nueva buferización # para leer el fichero de números aleatorios ob_start(); $f1=fopen("claves_beta","r"); fpassthru($f1); $claves=ob_get_contents(); ob_end_clean(); # convierto la cadena en una matriz # utilizando como "separador" el salto de línea # que había incluido detrás de cada número aleatorio # al generar el fichero aleatorio $matriz=explode("\r\n",$claves); # determino el tamaño de la matriz # de números aleatorios $num_claves=sizeof($matriz); # comparo la longitud de la cadena que # contiene el el fichero (ya con los bits invertidos) # con el tamaño de la matriz de números aleatorios # y determino el número de pasos que debo dar para la encriptación $pasos=((int)(strlen($cd)/$num_claves)); # diseño un bucle # que recorrerá la cadena e invertirá aquellos caracteres # cuya posición coincida con los valores de la tabla # de numeros aleatorios,el bucle for garantiza # que se recorrerá el fichero completo for ($i=0;$i<=$pasos;$i++){ foreach($matriz as $cambia){ if ( $i*$cambia<strlen($cd) ){ # extraigo un caracter $inv=substr($cd,$i*$num_claves+$cambia,1); # lo reemplazo por otro con los bits invertidos substr_replace($cd,~$inv,$i*$num_claves+$cambia,1); } } } # ahora guardamos la cadena codificada # en un fichero que será la página "encriptada" $f1=fopen("index1_clz.php","w"); fwrite($f1,$cd); fclose($f1); ?>
| Ver index1_clz.php encriptado |
<?
ob_start();
$f1=fopen("index1_clz.php","r");
fpassthru($f1);
$cadena = ob_get_contents();
ob_end_clean();
$cd=~$cadena ;
ob_start();
$f1=fopen("claves_beta","r");
fpassthru($f1);
$claves=ob_get_contents();
ob_end_clean();
$matriz=explode("\r\n",$claves);
$num_claves=sizeof($matriz);
$pasos=((int)(strlen($cd)/$num_claves));
for ($i=0;$i<=$pasos;$i++){
foreach($matriz as $cambia){
if ( $i*$num_claves+$cambia<strlen($cd) ){
$inv=substr($cd,$i*$num_claves+$cambia,1);
substr_replace($cd,~$inv,$i*$num_claves+$cambia,1);
}
}
}
echo $cd;
?>
| Ejecutar la desencriptación |
Creando un fichero con autoborrado
Aquí tienes la modificación del script de desencriptado con la que aparentemente solvento los problemas que te mencioné anteriormente... Este fichero que he utilizado como conejillo de Indias contiene includes y también código php que debe ejecutarse en el servidor...<? session_start(); $id=session_id(); $cadena=""; $pag="php32_xlz.php"; $f1=fopen($pag,"rb"); while (!feof($f1)) { $cadena .= fgets($f1, 1024); } fclose($f1); $cd=~$cadena; ob_start(); $f1=fopen("claves_beta","r"); fpassthru($f1); $claves=ob_get_contents(); ob_end_clean(); $matriz=explode("\r\n",$claves); $num_claves=sizeof($matriz); $pasos=((int)(strlen($cd)/$num_claves)); for ($i=0;$i<=$pasos;$i++){ foreach($matriz as $cambia){ if ( $i*$num_claves+$cambia<strlen($cd) ){ $inv=substr($cd,$i*$num_claves+$cambia,1); substr_replace($cd,~$inv,$i*$num_claves+$cambia,1); } } } $borrador="<? unlink('".$id.".php'); ?>"; $f1=fopen("$id.php","w"); fwrite($f1,$cd.$borrador); fclose($f1); $vete=$id.".php?".session_name()."=".session_id(); Header("Location:$vete"); ?>
| Ver fichero encriptado | Ejecutar el script anterior |
¿Será la definitiva?
<? session_start(); $id=session_id(); $cadena=""; $pag="php32_xlz.php"; $f1=fopen($pag,"rb"); while (!feof($f1)) { $cadena .= fgets($f1, 1024); } fclose($f1); $cd=~$cadena; ob_start(); $f1=fopen("claves_beta","r"); fpassthru($f1); $claves=ob_get_contents(); ob_end_clean(); $matriz=explode("\r\n",$claves); $num_claves=sizeof($matriz); $pasos=((int)(strlen($cd)/$num_claves)); for ($i=0;$i<=$pasos;$i++){ foreach($matriz as $cambia){ if ( $i*$num_claves+$cambia<strlen($cd) ){ $inv=substr($cd,$i*$num_claves+$cambia,1); substr_replace($cd,~$inv,$i*$num_claves+$cambia,1); } } } $f1=fopen("$id.php","w"); fwrite($f1,$cd); fclose($f1); include("$id.php"); unlink("$id.php"); ?>
| Ejecutar con el include famoso |
Mi duda metafísica
Llegado a este punto... me asaltan serias dudas... ¿será este un método válido para encriptación de ficheros?... ¿tendrá un montón de fallos que no he sabido ver?... ¿habré estado quemando pólvora en salvas?... Sinceramente... no lo sé... aquí te lo dejo para que lo pruebes si te apetece... abierto a sugerencias y críticas porque de lo único que estoy seguro es de que al menos ha sido un buen ejercicio de gimnasia mental... de eso es de lo único que estoy seguro... ;-)¿Paranoia encriptadora?
He vivido en carne propia los efectos de aquella antigua obsesión de supervivencia profesional basada en el secretismo
<?
session_start();
$id=session_id();
$cadena="";
$pag="php32_xlz.php";
$f1=fopen($pag,"rb");
while (!feof($f1)) {
$cadena .= fgets($f1, 1024);
}
fclose($f1);
$cd=~$cadena;
ob_start();
$f1=fopen("claves_beta","r");
fpassthru($f1);
$claves=ob_get_contents();
ob_end_clean();
$matriz=explode("\r\n",$claves);
$num_claves=sizeof($matriz);
$pasos=((int)(strlen($cd)/$num_claves));
for ($i=0;$i<=$pasos;$i++){
foreach($matriz as $cambia){
if ( $i*$num_claves+$cambia<strlen($cd) ){
$inv=substr($cd,$i*$num_claves+$cambia,1);
substr_replace($cd,~$inv,$i*$num_claves+$cambia,1);
}
}
}
$f1=fopen("$id.php","w");
fwrite($f1,$cd);
fclose($f1);
# activamos la buferización para evitar que
# los resultados de la ejecución del include
# sean enviados hacia el navegador
ob_start();
include("$id.php");
$salida=ob_get_contents();
ob_end_clean();
# una vez recogido en la variable
# salida el resultado de la ejecución del script
# desactivamos la bufferización y borramos el buffer
# escribimos el script de JavaScript
# e incluimos dentro de el la página
# codificandola con la funcion rawurlencode
$paranoia="<script language='JavaScript'>document.write(unescape('";
$paranoia .=rawurlencode($salida);
$paranoia.="'));</script>";
# enviamos el resultado al navegador
echo $paranoia;
# borramos el fichero del servidor
unlink("$id.php");
?>
| Con código fuente de lectura dificultosa |