TODOPIC

Microcontroladores PIC => * PROYECTOS * => Mensaje iniciado por: Picuino en 16 de Septiembre de 2015, 15:27:45

Título: Bootloader encriptado para Attiny88
Publicado por: Picuino en 16 de Septiembre de 2015, 15:27:45
Quiero hacer un pequeño bootloader a través de I2C encriptado con algoritmo XTEA o similar para un Attiny88

¿Alguien sabe si ya hay algún proyecto parecido?

Planeta9999 hizo uno similar para un PIC32: http://www.todopic.com.ar/foros/index.php?topic=40379

Otra duda que tengo es qué sistema de encriptación utilizar. ¿Con XTEA es suficiente?

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 16 de Septiembre de 2015, 15:37:02
El micro con el que voy a trabajar es un Attiny88 que tiene 512 bytes de ram y 8kbytes de Flash. Ejecuta 8 millones de instrucciones por segundo (4 millones de saltos)

He leído que hay 3 algoritmos TEA:
  TEA. Parece ser que está obsoleto. XTEA lo mejora en seguridad sin añadir complejidad
  XTEA Versión mejorada del anterior
  XXTEA versión mejorada del anterior. Ocupa más ROM.

¿Es así como he comentado?

Por lo que parece el XTEA es el mejor para mi caso (relativamente seguro y ocupa poco). La velocidad no me preocupa, porque el Attiny es rápido y actualizar el firmware no es algo que se haga todos los días.

Otro del que he leído es el RC4. Parece tan sencillo como el XTEA, pero no sé cuál será mejor para un Bootloader.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 17 de Septiembre de 2015, 00:14:33
Yo tampoco puedo comparar entre uno y otro.

Pero para que quede claro, estas pidiendo un bootloader que carga un archivo encriptado. O un bootlader encriptado?

El primero buscate un ejemplo de bootloader Y cada X bytes lo pasas por el "desencriptador" o tal ves si tenes un algoritmo que pueda manejarse con un stream de datos, es decir uno detras de otro, por ahi mejor.
El segundo, vas a tener que tener el desencriptador limpio, y luego que al comienzo si se cumple una condicion ( ejemplo un pin ) proceda a desencriptar el bootloader, cargarlo en la RAM y de alli ejecutarse. Sino deberias esecribir la FLASH, y si lo vas a hacer tenes que asegurarte luego de borrar unicamnete eso, seria uan perdida de espacio bastante grande.

Si no me equivoco hay un AN de Microchip con respecto a la implementacion del XTEA.

Con respecto a ejemplos:
https://code.google.com/p/picoboot/
https://code.google.com/p/picoboot/source/browse/trunk/picobootSerial.S

Le falta todo lo demas, la encriptacion + buffer, etc. Tenes que recordar que en C tenes el que normalmente se llama c_init, que es el que inicializa las variables, el stack y varias verduras mas para que funcione.

Tmbien tenes :

http://www.avrfreaks.net/projects
Busca por bootloader

Lo primero que salio en google. Utiliza la UART, que no te costaria nada cambiarlo al I2C
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 17 de Septiembre de 2015, 10:08:20
Lo que quiero es un bootloader que reciba un archivo encriptado, lo desencripte y lo escriba en la flash.

Lo de utilizar I2C es porque es el estandar serie de ese chip (no tiene UART y no quiero hacerla por soft)
La rutina I2C ya la tengo programada y funciona, pero para ahorrar espacio me gustaría compartirla con la aplicación y no tengo claro cómo hacerlo (con punteros, memoria global compartida, ...)

El programa para decodificar XTEA ya lo tengo funcionando en el PC. Me falta una buena implementación en el Atmel.

El picoboot ya lo había visto, pero es de otro tipo. Simula una UART por soft y no encripta ni comparte rutinas.

En AVRfreaks había encontrado un enlace muy interesante sobre Bootloaders:
   http://www.avrfreaks.net/forum/faq-c-writing-bootloader-faq?page=all

Resuelve muchas dudas prácticas

Ahora me falta implementarlo y no quiero inventar la rueda. Si hay otro similar al que quiero hacer, lo adapto y listo.
También me gustaría ver otros con alguna de las características que quiero, para inspirarme.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 17 de Septiembre de 2015, 10:19:36
Mi rutina I2C trata prácticamente todos los casos y ocupa 494 bytes. Debería reutilizarla entre bootloader y aplicación.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 17 de Septiembre de 2015, 10:51:02
Citar
La rutina I2C ya la tengo programada y funciona, pero para ahorrar espacio me gustaría compartirla con la aplicación

¿Es decir que vaya el bootloader + aplicacion todo encriptado?
¿o queres decir que queres compartir la rutina del I2C tanto para el bootloader como para la aplicacion?

Yo decia que del picobot tomaras unicamente la parte de grabar la EEPROM + vectores de reset,etc y que solo crearas la parte de I2C el cual te comunicarias con eso. No es necesario una UART, en ves que exista una funcion que devuelve valores desde la UART lo que harias es tomar datos pero de ahora una funcion que maneja el I2C. Por eso no pense que habia demasiado cambio.

El otro tema es, en que lenguaje estas haciendo las cosas?.
Tu rutina esta en C? y queres compartirla con ambos ( bootloader + aplicacion ) entonces primero vas a tener que iniciar stack/variables/etc, lo que es igual a llamar al c_init/startup y te lo da atmel y lo pone siempre en el vector de reset.
Luego podrias hacer tu propia seccion para el bootloader, digamos al final de la memoria y hacer la funcion en C

http://www.atmel.com/webdoc/AVRLibcReferenceManual/mem_sections_1c_sections.html
http://www.atmel.com/Images/doc32158.pdf

void bootloader() __attribute__((section("name")));

void bootloader() {

  Esto llamado directamente desde el main() o si queres llamarlo desde el c_init/startup y que luego llame al main
  Debo acualizar? Sino salgo y que siga corriendo el programa.
  Sino grabo la Flash excepto la seccion del bootloader, es decir .text , .intvect, etc.
  Y produzco un reset del micro, o lo cuelgo para siempre
}

Eso en C, es lo que se me ocurre, si queres hacer mezcla ASM/C se puede complicar un poco mas, ya que podrias llamar a las funciones I2C desde el ASM pero hay que empezar a respetar las convenciones que tienen para llamarse, etc. Pero si vas a utilizar C si o si tiene que correr tu c_init/startup.
Tambien las funciones de I2C deberian incluirse dentro de la seccion del bootloader ya que no van a poder ser modificadas mientras se estan utilizando, la otra es mover estas funciones a la RAM y usarlas desde alli, pero eso va a depender del micro si es que puede correr codigo desde la RAM.

Lo feo que encuentro de esto, al volver a reescribir hasta los vectores de interrupciones, es que si por algun motivo no se llega a grabar, ejemplo se corta apenas comienza, ya no va a entrar al startup nunca mas. Lo cual puede que sea mejor tambien reubicar los vectores de resets (si es que se puede obvio) y dejar el bootloader + startup/c_init en el comienzo y evitar que este lugar sea grabado.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: planeta9999 en 17 de Septiembre de 2015, 11:06:06
.

A cualquier bootloader estandar es muy fácil implementarle la rutina para desencriptar XTEA.

En Wikipedia tienes la rutina XTEA en C, practicamente lista para meterla en cualquier código en C, bien para PC o microcontroladores.
https://es.wikipedia.org/wiki/Extended_Tiny_Encryption_Algorithm#Implementaci.C3.B3n_en_C

Incluso te dan la rutina para encriptar, que es casi igual a la de desencriptar, solo que en la fórmula en vez de sumar, resta. De ahí lo pillé yo para mi bootloader, así que está más que probado y funciona a la perfección.

El XXTEA no lo conocía, pero también lo tienes en Wikipedia, y también te dan el código en C, para implementarlo en un momento.
https://en.wikipedia.org/wiki/XXTEA#Reference_code

Y si quieres usar RC4, de nuevo Wikipedia te da toda la información, incluido el código fuente en C para implementarlo.
https://en.wikipedia.org/wiki/RC4#RC4_variants

Lo que necesitarás, y creo que no lo has mencionado, es un encriptador XTEA, yo colgué una demo del ejecutable del mío, pero no es de código abierto, y por lo tanto la clave de encriptación no la puedes cambiar. Tampoco es muy complicado hacerse un encriptador, yo partí de un fuente en C para Visual Studio, al que añadí la rutina para abrir el archivo HEX original, la rutina de encriptación y la rutina para grabar el nuevo archivo encriptado.

Para el microcontrolador, no te compliques la vida, cualquier bootloader estandar te vale, y meterle la rutina de desencriptación XTEA se hace en unos minutos. Donde tendrás el curro realmente es en hacer el programa de encriptación, recomendable usar un entorno visual como Visual C++ o Visual Basic.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 17 de Septiembre de 2015, 11:23:25
Podrias hacerlo en python... O buscarla por internet:

https://pypi.python.org/pypi/xtea/0.4.0
http://code.activestate.com/recipes/496737-python-xtea-encryption/

Y no necesitarias de una GUI,etc, ademas lo agregas a tu coleccion de utilidades de python :)
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 17 de Septiembre de 2015, 12:32:27
Por partes:

1. El bootloader tiene una rutina de tratamiento del I2C de unos 500bytes
La aplicación también usa I2C. No tiene sentido que duplique el código. Lo mejor es utilizar la misma rutina que ya tiene el bootloader, llamándola desde la aplicación.
Así ahorro espacio.
El problema es llamar a una función del bootloader desde otro código fuente distinto. Hay que ponerse de acuerdo en dónde van a estar las variables (el buffer por ejemplo).
Hay muchas soluciones y no sé cual será la mejor. Creo que me voy a decantar por los punteros, que parece más sencillo que la memoria global fija.

2. Utilizo siempre C. Si hace falta algo de ASM, lo meto en una función C.

3. Miraré lo del  c_init/startup, que no lo conozco.

4. La recuperación ante errores es otro tema que estoy estudiando. Quiero combinarlo con una comprobación de memoria.
El bootloader se inicia primero. Comprueba la Flash. Si el checksum no es correcto, no inicia la aplicación y se queda en modo bootloader.

5. En el vector de reset quiero dejar fijo un salto al bootloader
    El vector de reset de la aplicación, se reubica al final de la flash, antes del bootloader
    Al finalizar el bootloader, salta a esta dirección reubicada.

    Ante un reset siempre se inicia el bootloader, que salta a la aplicación al cabo de un tiempo. (Como en el Arduino)
    Si se recibe en el primer segundo algún dato I2C, entonces continua en bootloader hasta que le llegue el final del archivo.

    La aplicación tendrá una orden I2C que provoque un reset software. Así tendré varias formas de entrar en el bootloader.

6. El XTEA que tengo funcionando es el de Wikipedia, pero me parecía que no estaba optimizado para micros de 8 bits.
    Lo haré yo mismo.

7. En cuanto al RC4, el problema no es implementarlo, que es muy fácil.
    Lo que quiero sabe es si es mejor opción que el XTEA.

8. La aplicación del lado PC no sé si va a existir.
    La carga del bootloader tiene que ir por I2C, de forma que lo voy a tranferir a partir de un Arduino.
    Cargas el programa en el Arduino y él se encarga de grabar el nuevo firmware en la placa.
    No hay opciones, y el IDE es el de Arduino.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 17 de Septiembre de 2015, 12:39:44
9. La solución Python no me gusta porque supone que el cliente tendrá Python instalado o que lo va descargar en formato portable.
En cualquier caso ocupa mucho. Preferiría utilizar LUA o una aplicación compilada (VisualBasic o similar)

En cualquier caso el Arduino tendrá que estar ahí para traducir a I2C

Otra solución es utilizar el puerto serie y una UART software por los mismos pines que el I2C. Me lo pensaré.
Pero Arduino sigue siendo necesario para convertir USB a UART. La mayoría de los usuarios Arduino no tienen un conversor USB-RS232 y quiero hacerlo fácil para ellos (que muchas veces no tienen mucho nivel)

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 17 de Septiembre de 2015, 14:00:12
Solo quiero corregirme una cosa en AVR-LIBC el archivo de startup/c_init o como se le quiera llamar, que es el que esta ubicado en el vector de reset se llama:

crt0.S o crt1.S

Este archivo lo que hace es como ya dije inicializar el stack, copiar los valores de una tabla desde la flash a la RAM, para inicializar las variables de la seccion .data (variables inicializadas), inicializa registros para los saltos indirectos. y creo que nada masi.

Citar
La aplicación también usa I2C. No tiene sentido que duplique el código. Lo mejor es utilizar la misma rutina que ya tiene el bootloader, llamándola desde la aplicación.
Así ahorro espacio.
El problema es llamar a una función del bootloader desde otro código fuente distinto. Hay que ponerse de acuerdo en dónde van a estar las variables (el buffer por ejemplo).
Hay muchas soluciones y no sé cual será la mejor. Creo que me voy a decantar por los punteros, que parece más sencillo que la memoria global fija.

Nuevamente si tenes funciones en C, compiladas desde C, apenas entra el ASM generado va a guardar los datos al stack y van a tratar de utilizar todas las variables inicializadas como si ahi estuvieran, si vos quitas el esa inicializacion del vector de reset entonces no hay ciencia cierta de que pueda salir de esa funcion, aunque podrias llamarlo luego desde tu bootloader, pero deberias modificar ese codigo ASM. Asi que estas un poco como obligado a hacerlo. En ves de llamar a tu bootloader desde el vector de reset, usas esta funcion, usas el main() para tu bootloader, ya que ahi salta siempre estos codigos.

Código: C
  1. #ifdef __AVR_ASM_ONLY__
  2.         XJMP    main
  3. #else   /* !__AVR_ASM_ONLY__ */
  4.         XCALL   main
  5.         XJMP    exit
  6. #endif  /* __AVR_ASM_ONLY__ */
  7. ;       .endfunc

La ubicacion esta a tu gusto, veras los pros/cons de cada uno.
El main(bootloader) ubicado al comienzo, todo lo demas apartir de la proxima pagina, I2C, todo tu programa. Sus ventajas es que esta todo juntito no hay problemas, las desventajas es que no podes reescribir los vectores de interrupcion, a no ser que crees una tabla aparte poniendole todos saltos y ubicandola en otro lugar.

La otra es ponerlo al final de la flash. Lo bueno de esto es que se podria reescribir, ya que una ves ejecutado la inicializacion ya no te importa mas esa rutina de crt0.S y podes trabajar en C tranquilo, desventajas perder algo mas de espacio.

Con respecto a la ubicacion de los I2C, creo que hay 2 opciones.
- Una es como decis, la de poner punteros a la funcion en valores de memoria fijos ( tal ves al comienzo del todo el codigo ), tomar ese valor y llamarlas.
- La otra es poner la funcion de I2C junto con el bootloader si es que entra en una pagina todo. Suponiendo que no vuelva a cambiarse (por que funciona perfectamente) y ademas todo va a depender si hay espacio para eso E imagino que vas a tener que realizar lo mismo con punteros pero ahora para  tu programa.

No entiendo por que tendrias problemas con el buffer, simplemente crealo en C, que lo acomode solo el linker y lo llamas desde ahi. Total esta en la RAM. Si queres utilizar el I2C en C entonces ya va a estar creado todo lo de las variables

Citar
4. La recuperación ante errores es otro tema que estoy estudiando. Quiero combinarlo con una comprobación de memoria.
El bootloader se inicia primero. Comprueba la Flash. Si el checksum no es correcto, no inicia la aplicación y se queda en modo bootloader.

Normalmente tenes 2 comprobaciones de memoria, una en el envio de datos, por ejemplo cada 4 bytes  , enviar 1 byte de cheksum. y la otra es cuando grabas y comprobas lo grabado.
Lo que si hay que ingeniarsela que ante un corte de corriente etc que haga que se resetee mientras grababa las primeras posiciones no afecte en nada. Esto es lo mas complicado. Ya que como minimo necesitarias de esos algunos bytes como para tener la rutina de inicializacion + vectores de interrupcion (todo por el I2C en C), sino con que grabara unicamente el vector de reset ya no habia forma de errarlo, no creo que justo falle en el primer byte .
Igual esto puede pasar casi nunca. pero mejor intentar prevenir que curar.

Citar
7. En cuanto al RC4, el problema no es implementarlo, que es muy fácil.
    Lo que quiero sabe es si es mejor opción que el XTEA.
XTEA es mas seguro. Si es que a eso vamos. No importa tanto lo eficiente, si esto se va a ejecutar solo cuando vayas a grabarlo.

Citar
. La solución Python no me gusta porque supone que el cliente tendrá Python instalado o que lo va descargar en formato portable.
En cualquier caso ocupa mucho. Preferiría utilizar LUA o una aplicación compilada (VisualBasic o similar)

No entiendo por que debe tener python instalado el cliente, vos provees con el archivo encryptado con la extension que quieras, se envia encryptado al micro y en el micro antes de grabarlo se desencripta. Y una clave que solo tengas vos y este dentro del integrado nomas.

Sino no tiene sentido.
Es vulnerable si el programa "cliente" lo desencripta y luego envia sin encriptar
Y menos que menos si se lo das desencriptado y que el programa lo encripte para que el micro lo desencripte.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 17 de Septiembre de 2015, 18:53:05
El problema de fallo de corriente en el primer byte no le veo solución sencilla. Lo pensaré con calma.

Creo que al final será mejor poner el bootloader en las últimas posiciones.

El problema que veo para compartir memoria es que en gnu-avr no puedes decir al compilador dónde va a estar una variable en RAM. Siempre lo elige por tí el linker. No es como en el PIC.
Eso es algo que echo de menos. Se puede hacer con las opciones del linker, pero por lo poco que he visto no es nada intuitivo.
De forma que utilizar una dirección fija de RAM no parece sencillo. Lo mejor es utilizar un puntero a la dirección de RAM.

Pero la rutina de interrupciones ¡es una función sin parámetros! y estamos en las mismas. ¿Cómo le digo dónde está el buffer? No termino de entender bien cómo hacerlo con el linker.


La inicialización la puedo hacer yo en C y casi lo prefiero. Así controlo exactamente qué hace el código. Lo estudiaré.


Entonces elejiré el XTEA como método de encriptación

Lo del Python es para tener una aplicación que lea el fichero encriptado y lo mande encriptado al micro. Mi solución va a ser hacerlo mediante un programa de Arduino.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 21 de Septiembre de 2015, 16:39:36
Al final he optado por utilizar una UART software. Lo he codificado en C y me ha ocupado sólo 100bytes.

Luego he vuelto a revisar la rutina UART software en ensamblador del picoboot y sólo ocupa 26 bytes !!!

Para un bootloader, que es pequeño y se modifica poco, creo que no merece la pena programar en c.

Ahora a por el XTEA.

¿Alguien conoce una rutina en ensamblador para el Attiny?
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 21 de Septiembre de 2015, 16:53:25
Yo no poseo el codigo. Pero si tenes realizada la rutina en C, yo te ayudo a pasarlo a ASM. Vos tambien luego diras si lo vas a llamar desde una funcion C o no, asi lo unico que se le agregaria es lo de salvar los registros.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 21 de Septiembre de 2015, 18:23:11
La rutina es sencilla en c:

Código: [Seleccionar]
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;
    for (i=0; i < num_rounds; i++) {
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
        sum -= delta;
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
    }
    v[0]=v0; v[1]=v1;
}

El problema está en que utiliza datos bastante grandes y sobrepasa la capacidad de los registros disponibles en c.
Habría que salvar los registros antes del ensamblador.

Por la ram no hay problema. Hay 512 bytes disponibles.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 21 de Septiembre de 2015, 18:24:09
Yo creo que el "unsigned int i" y el "unsigned int num_rounds" se pueden sustituir por dos char.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 21 de Septiembre de 2015, 18:26:44
Si además la key se hace global, quedaría así:

Código: [Seleccionar]
uint32_t const key[4] = {
    0x12345678,
    0x12345678,
    0x12345678,
    0x12345678,
}

void decipher(char num_rounds, uint32_t v[2]) {
    uint32_t v0 = v[0];
    uint32_t v1 = v[1];
    uint32_t delta = 0x9E3779B9;
    uint32_t sum = delta * num_rounds;
    while(num_rounds--) {
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
        sum -= delta;
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
    }
    v[0] = v0;
    v[1] = v1;
}
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 21 de Septiembre de 2015, 18:45:58
Listo Picuino. Esta noche o mañana cuando tengo un tiempito lo hago.

El bootloader se ejecuta antes que el crt0 o despues ?, es para saber si manejarme con el stack o si puedo elegir aleatoriamente cualquier posicion de la RAM.

Citar
Habría que salvar los registros antes del ensamblador.

Eso depende.. Si todavia no iniciaste C con el crt0/1 entonces puedo utilizar los registros a mi gusto, si lo iniciaste entonces debo guardar los registros en el stack y crear las variables en el stack para manejarme.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 21 de Septiembre de 2015, 18:46:29
Con algunos cambios más:

Código: [Seleccionar]
#define XTEA_DELTA  0x9E3779B9
#define NUM_ROUND   32L

uint32_t const key[] = {
   // Cambiar los siguientes valores por la key
   0x12345678, 0x12345678, 0x12345678, 0x12345678,  
}

void decipher(uint32_t v[2]) {
   uint32_t v0 = v[0];
   uint32_t v1 = v[1];
   uint32_t sum =  XTEA_DELTA * NUM_ROUND;
   char num_rounds = 32;
   while(num_rounds--) {
      v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
      sum -= XTEA_DELTA;
      v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
   }
   v[0] = v0;
   v[1] = v1;
}

He usado el valor recomendado para el número de rondas (32)
Creo que el algoritmo no ha cambiado.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 21 de Septiembre de 2015, 18:50:58
Gracias Killer. Creo que al final haré todo en ensamblador para que sea más pequeño.
No hay que preocuparse por la ram. Está toda disponible para el bootloader.

Los datos llegan por la UART en grupos de 64 bytes (una página flash) + checksum

Una vez comprobados, se decodifican en grupos de 4 bytes (el algoritmo XTEA),  se guardan en la memoria temporal flash y se escriben en flash.

Recuerda que es para un Attiny. Yo estoy acostumbrado al PIC y eso me está dando algún dolor de cabeza. Son bien distintos.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: planeta9999 en 21 de Septiembre de 2015, 21:38:22

He usado el valor recomendado para el número de rondas (32)



Más seguro si lo haces a 64 rondas, así lo tengo yo en mi bootloader.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 22 de Septiembre de 2015, 03:34:29
Esto ya lo tengo realizado en ASM:

Código: C
  1. while(num_rounds--) {
  2.         v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
  3.         sum -= delta;
  4.         v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
  5.     }

El tema es que no me gusta como esta hecho.. por que esta todo lineal por asi decirlo, no quiero reducir mas la funcion. Aunque todo se ve agrandado por 4 debido a que hay que manejarse a 32bits
Como se puede observar hay codigo "repetido" ya que para las lineas de v1 -= xxx y las de v0 -= xxx son casi iguales. entonces quiero hacer un codigo en el que los puedan usar a ambos

Código: ASM
  1. Loop_while
  2.         ;Rotar todos
  3.  
  4.         MOVW    Vtemp0[0],V0[0] // Vtemp0 para (v0<<4) y Vtemp1 para (V0 >> 5)
  5.         MOVW    Vtemp0[2],V0[2]
  6.         MOVW    Vtemp1[0],V0[0]
  7.         MOVW    Vtemp1[2],V0[2]
  8.  
  9.         LDI     R0,4
  10. RotateLeftv0                    // (v0 << 4)
  11.         LSL     Vtemp0[0]
  12.         ROL     Vtemp0[1]
  13.         ROL     Vtemp0[2]
  14.         ROL     Vtemp0[3]       // Por ser de 32 bits se deberian perder los bits que salgan de aca
  15.         DEC     R0
  16.         BRNE    RotateLeftv0
  17.  
  18.         LDI     R0,5
  19. RotateRightv0                   // (V0 >> 5 )
  20.         LSR     Vtemp1[3]
  21.         ROR     Vtemp1[2]
  22.         ROR     Vtemp1[1]
  23.         ROR     Vtemp1[0]
  24.         DEC     R0
  25.         BRNE    RotateRightv0
  26.  
  27.         EOR     Vtemp0[0],Vtemp1[0]     //  (v0 << 4) ^ (v0 >> 5)
  28.         EOR     Vtemp0[1],Vtemp1[1]
  29.         EOR     Vtemp0[2],Vtemp1[2]
  30.         EOR     Vtemp0[3],Vtemp1[3]
  31.  
  32.         ADD     Vtemp0[0],V0[0]         //  ((v0 << 4) ^ (v0 >> 5)) + v0
  33.         ADC     Vtemp0[1],V0[1]         // Vtemp0 = ((v0 << 4) ^ (v0 >> 5)) + v0
  34.         ADC     Vtemp0[2],V0[2]
  35.         ADC     Vtemp0[3],V0[3]
  36.  
  37.         MOVW    Vtemp1[0],sum[0]
  38.         MOVW    Vtemp1[2],sum[2]
  39.  
  40.         MOV     R0,SUM[1]               // sum>>11 & 3
  41.         LSR     R0
  42.         ANDI    R0,0x0C                 // 0000 aa00
  43.         ADD     ZL,R0                   // Le sumo el valor de R0 o lo que es igual a 4 * index
  44.         LD      Aux[0],Z+               // key[sum>>11&3]
  45.         LD      Aux[1],Z+
  46.         LD      Aux[2],Z+
  47.         LD      Aux[3],Z+
  48.  
  49.         ADD     Vtemp1[0],Aux[0]        // sum + key[(sum>>11) & 3]
  50.         ADC     Vtemp1[1],Aux[1]        // Vtemp1 = sum + key[(sum>>11) & 3]
  51.         ADC     Vtemp1[2],Aux[2]
  52.         ADC     Vtemp1[3],Aux[3]
  53.  
  54.         EOR     Vtemp0[0],Vtemp1[0]     //  (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])
  55.         EOR     Vtemp0[1],Vtemp1[1]     //   Vtemp[0]
  56.         EOR     Vtemp0[2],Vtemp1[2]
  57.         EOR     Vtemp0[3],Vtemp1[3]
  58.  
  59.         SUB     V1[0],Vtemp0[0]         // v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])
  60.         SBC     V1[1],Vtemp0[1]
  61.         SBC     V1[2],Vtemp0[2]
  62.         SBC     V1[3],Vtemp0[3]         // si ocurrio overflow ocurrio, lo lamento
  63.  
  64.         // Resta de Suma
  65.  
  66.         SUB     sum[0],XTEA_DELTA[0]    // sum -= XTEA_DELTA;
  67.         SBC     sum[1],XTEA_DELTA[1]
  68.         SBC     sum[2],XTEA_DELTA[2]
  69.         SBC     sum[3],XTEA_DELTA[3]
  70.  
  71.         // Comienzo de la segunda operacion
  72.  
  73.         LDI     ZL,0x00                 // Renuevo el valor de las keys
  74.  
  75.         MOVW    Vtemp0[0],V1[0]
  76.         MOVW    Vtemp0[2],V1[2]
  77.         MOVW    Vtemp1[0],V1[0]
  78.         MOVW    Vtemp1[2],V1[2]
  79.  
  80.         LDI     R0,5
  81. RotateLeftv1                    // (v1 << 4)
  82.         LSL     Vtemp0[0]
  83.         ROL     Vtemp0[1]
  84.         ROL     Vtemp0[2]
  85.         ROL     Vtemp0[3]       // Por ser de 32 bits se deberian perder los bits que salgan de aca
  86.         DEC     R0
  87.         BRNE    RotateLeftv1
  88.  
  89.         LDI     R0,5
  90. RotateRightv1                   // (V1 >> 5 )
  91.         LSR     Vtemp1[3]
  92.         ROR     Vtemp1[2]
  93.         ROR     Vtemp1[1]
  94.         ROR     Vtemp1[0]
  95.         DEC     R0
  96.         BRNE    RotateRightv1
  97.  
  98.         EOR     Vtemp0[0],Vtemp1[0]     //  (v1 << 4) ^ (v1 >> 5)
  99.         EOR     Vtemp0[1],Vtemp1[1]
  100.         EOR     Vtemp0[2],Vtemp1[2]
  101.         EOR     Vtemp0[3],Vtemp1[3]
  102.  
  103.         ADD     Vtemp0[0],V1[0]         //  ((v1 << 4) ^ (v1 >> 5)) + v1
  104.         ADC     Vtemp0[1],V1[1]         // Vtemp0 = ((v1 << 4) ^ (v1 >> 5)) + v1
  105.         ADC     Vtemp0[2],V1[2]
  106.         ADC     Vtemp0[3],V1[3]
  107.  
  108.         MOVW    Vtemp1[0],sum[0]
  109.         MOVW    Vtemp1[2],sum[2]
  110.  
  111.         MOV     R0,SUM[0]               // sum & 3
  112.         ANDI    R0,0x03                 // 0000 00aa
  113.         ADD     ZL,R0                   // Le sumo el valor de R0 o lo que es igual a 4 * index
  114.         LD      Aux[0],Z+               // key[sum&3]
  115.         LD      Aux[1],Z+
  116.         LD      Aux[2],Z+
  117.         LD      Aux[3],Z+
  118.  
  119.         MOVW    Vtemp1[0],sum[0]
  120.         MOVW    Vtemp1[2],sum[2]
  121.  
  122.         ADD     Vtemp1[0],Aux[0]        // sum + key[sum & 3]
  123.         ADC     Vtemp1[1],Aux[1]        // Vtemp1 = sum + key[sum & 3]
  124.         ADC     Vtemp1[2],Aux[2]
  125.         ADC     Vtemp1[3],Aux[3]
  126.  
  127.         EOR     Vtemp0[0],Vtemp1[0]     //  (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3])
  128.         EOR     Vtemp0[1],Vtemp1[1]     //  Vtemp0
  129.         EOR     Vtemp0[2],Vtemp1[2]
  130.         EOR     Vtemp0[3],Vtemp1[3]
  131.  
  132.         SUB     V0[0],Vtemp0[0]         // v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3])
  133.         SBC     V0[1],Vtemp0[1]
  134.         SBC     V0[2],Vtemp0[2]
  135.         SBC     V0[3],Vtemp0[3]         // si ocurrio overflow ocurrio, lo lamento
  136.  
  137.         DEC     Round
  138.         BRNE    Loop_while

Lo otro feo es que utilize con eso casi todos los registros del core   :), me quedo solo el de R0 que lo uso de temporal como para las operaciones...
Lo hice asi solo para evitar el ciclo extra que hay a la SRAM

Código: [Seleccionar]
R1  = Round
R2  = Aux[0]
R3  = Aux[1]
R4  = Aux[2]
R5  = Aux[3]
R6  = V1[0]
R7  = V1[1]
R8  = V1[2]
R9  = V1[3]
R10 = sum[0]
R11 = sum[1]
R12 = sum[2]
R13 = sum[3]
R14 = V0[0]
R15 = V0[1]
R16 = V0[2]
R17 = V0[3]
R18 = Vtemp0[0]
R19 = Vtemp0[1]
R20 = Vtemp0[2]
R21 = Vtemp0[3]
R22 = Vtemp1[0]
R23 = Vtemp1[1]
R24 = Vtemp1[2]
R25 = Vtemp1[3]
R26 = XL
R27 = XH
R28 = YL
R29 = YH
R30 = ZL
R31 = ZH

Ahora me voy a dormir por que son casi 3am, mañana lo achico para que ocupe menos espacio y termino la otra parte.

Citar
Los datos llegan por la UART en grupos de 64 bytes (una página flash) + checksum

Supongo que en la UART se va nicluyendo el cheksum apenas van llegando.
Una ves llegado los 64bytes y comprobado, se procede a decodificarlo y luego a grabarlos.
Voy a pensar como que hay un buffer de 64 bytes empezando en 0x100(Comienzo de SRAM) hasta 0x139, se decodifica todo esas 64 bytes y sale de esta rutina para que se pueda programar. Tambien se podria aprovechar toda la RAM para crear 2 buffers de 64 bytes. asi mientras se llena uno mediante interrupciones, el otro va decodificandose/grabandose.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 22 de Septiembre de 2015, 07:46:38
El algoritmo UART utiliza pooling. No se pueden utilizar interrupciones.

No hace falta optimizar tiempos:
   A 115200 baud, se reciben 64 bytes + checksum en aproximadamente 6 milisegundos.
   Luego se decodifican. He calculado aproximadamente 1 ms por cada 8 bytes a partir de tu rutina. En total 8 ms por página de 64 bytes.
   A continuación se envían a grabar (unos 2 milisegundos) que se puede hacer mientras se recibe otra página.
   En total calculo unos 15ms por página.
   Tiempo total = 1.8 segundos en grabar 8kb de flash.

No hay que preocuparse por optimizar ese tiempo para nada.

Lo que más me preocupa es la memoria. Cuanto más pequeño sea, mejor.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 22 de Septiembre de 2015, 07:49:41
Más seguro si lo haces a 64 rondas, así lo tengo yo en mi bootloader.

Ese punto no me queda muy claro. En Wikipedia dicen que para hacer 64 rondas, es necesario hacer 32 ciclos, porque el algoritmo hace 2 rondas por ciclo:
https://en.wikipedia.org/wiki/XTEA
Citar
The recommended value for the "num_rounds" parameter is 32, not 64, as each iteration of the loop does two Feistel-cipher rounds
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 22 de Septiembre de 2015, 08:05:51
Paper de los autores proponiendo el XTEA:
http://www.cix.co.uk/~klockstone/xtea.pdf

Comentario y rutina:
Citar
 v gives the plain text of 2 words,
  k gives the key of 4 words,
  N gives the number of cycles, 32 are recommended,
  if negative causes decoding, N must be the same as for coding,
  if zero causes no coding or decoding.
  assumes 32 bit \long" and same endian coding or decoding

tean( long * v, long * k, long N) {
   unsigned long y=v[0], z=v[1], DELTA=0x9e3779b9 ;
   if (N>0) {
      /* coding */
      unsigned long limit=DELTA*N, sum=0 ;
      while (sum!=limit)
         y += (z<<4 ^ z>>5) + z ^ sum + k[sum&3],
         sum +=DELTA,
         z += (y<<4 ^ y>>5) + y ^ sum + k[sum>>11 &3] ;
   }

   else {
      /* decoding */
      unsigned long sum=DELTA*(-N) ;
      while (sum)
         z -= (y<<4 ^ y>>5) + y ^ sum + k[sum>>11 &3],
         sum -=DELTA,
         y -= (z<<4 ^ z>>5) + z ^ sum + k[sum&3] ;
   }
   v[0]=y;
   v[1]=z ;
   return;
}

El comentario de los autores:

  N gives the number of cycles, 32 are recommended,
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 22 de Septiembre de 2015, 08:12:27
En base a esto, cambiando N por 32:

Código: [Seleccionar]
#define XTEA_DELTA  0x9E3779B9
uint32_t const xtea_key[] = {
   0x12345678, 0x12345678, 0x12345678, 0x12345678,
}

void xtea_decipher(uint32_t *data) {
   uint32_t data0 = data[0];
   uint32_t data1 = data[1];

   /* decoding */
   uint32_t sum = XTEA_DELTA * 32;
   while (sum) {
      data1 -= (((data0<<4) ^ (data0>>5)) + data0) ^ (sum + xtea_key[(sum>>11) & 3];
      sum -= XTEA_DELTA;
      data0 -= (((data1<<4) ^ (data1>>5)) + data1) ^ (sum + xtea_key[sum & 3] ;
   }
   v[0] = data0;
   v[1] = data1;
}
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 22 de Septiembre de 2015, 08:18:21
No me queda claro si será mejor comprobar que (sum == 0) o contar directamente el número de rondas.

He comprobado las dos rutinas y son iguales (excepto en la condición de salida del bucle)
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 22 de Septiembre de 2015, 09:29:42
Rutina en Python para probar el algoritmo XTEA:

Código: [Seleccionar]
import random, ctypes

NUM_ROUNDS = 32
XTEA_DELTA = 0x9E3779B9
xtea_key = [random.randrange(0, 0xFFFFFFFF) for n in range(4)]


def xtea_encode(data):
   data0 = data[0]
   data1 = data[1]
   suma = 0
   rounds = 32
   while(rounds):
      data0 += (((data1<<4) ^ (data1>>5)) + data1) ^ (suma + xtea_key[suma & 3])
      data0 = uint32(data0)
      suma = uint32(suma + XTEA_DELTA)
      data1 += (((data0<<4) ^ (data0>>5)) + data0) ^ (suma + xtea_key[(suma>>11) & 3])
      data1 = uint32(data1)
      rounds -= 1
   data[0] = data0
   data[1] = data1


def xtea_decode(data):
   data0 = data[0]
   data1 = data[1]
   suma = uint32(XTEA_DELTA * 32);
   rounds = 32
   while(rounds):
      data1 -= uint32((((data0<<4) ^ (data0>>5)) + data0) ^ (suma + xtea_key[(suma>>11) & 3]))
      data1 = uint32(data1)
      suma = uint32(suma - XTEA_DELTA)
      data0 -= uint32((((data1<<4) ^ (data1>>5)) + data1) ^ (suma + xtea_key[suma & 3]))
      data0 = uint32(data0)
      rounds -= 1
   data[0] = data0
   data[1] = data1


def test_xtea(data):
   org0, org1 = data
   xtea_encode(data)
   enc0, enc1 = data
   xtea_decode(data)
   dec0, dec1 = data
   if (dec0 == org0 and dec1 == org1 and
       enc0 != org0 and enc1 != org1):
      return True
   else:
      print '\nError en XTEA'
      print '  Codificado   :', encode_data
      print '  Decodificado :', decode_data
      return False
  

def uint32(data):
    return ctypes.c_uint32(data).value

    
def main():
   msgs = 1000
   print('Testing %d messages' % msgs)
   random.SystemRandom()
   data = [0, 1]
   for i in range(msgs):
      data[0] = random.randrange(0, 0xFFFFFFFF)
      data[1] = random.randrange(0, 0xFFFFFFFF)
      if test_xtea(data) == False:
         break;        
   print("Test End")

  
main()

Voy a probar con ella a hacer simplificaciones a la rutina de decodificacion.

Saludos.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 22 de Septiembre de 2015, 09:55:40
El código se puede simplificar así:

Código: [Seleccionar]
# data0 = registro temporal 32 bits = 4 bytes
# data1 = registro temporal 32 bits = 4 bytes
# Ta    = registro temporal 32 bits = 4 bytes
# Tb    = registro temporal 32 bits = 4 bytes
# suma  = registro temporal 32 bits = 4 bytes
# rounds = registro temporal 8 bits = 1 byte
# r1    = registro temporal  8 bits = 1 byte

def xtea_sub1():
   global Ta, Tb, r1, suma
   Tb = Ta    
   Ta <<= 4
   Tb >>= 5
   xtea_sub3()  # goto xtea_sub3  


def xtea_sub2():
   global Ta, Tb, r1, suma
   Tb = xtea_key[r1]
   Tb += suma
   xtea_sub3()  # asm continue in xtea_sub3


def xtea_sub3():
   global Ta, Tb, r1, suma
   Ta ^= Tb

  
def xtea_decode(data):
   global Ta, Tb, r1, suma
   data0 = data[0]
   data1 = data[1]

   suma = uint32(XTEA_DELTA * 32);
   rounds = 64
   while(rounds):
      Ta = data0
      xtea_sub1()
      Ta += data0
      if not (rounds & 1):
         r1 = (suma>>11) & 3    
      else:
         r1 = suma & 3
      xtea_sub2()
      data1 -= Ta
      data1 = uint32(data1)
      if not (rounds & 1):
         suma -= XTEA_DELTA
         suma = uint32(suma)
      data0, data1 = data1, data0
      rounds -= 1
      
   data[0] = data0
   data[1] = data1
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 22 de Septiembre de 2015, 11:42:32
Citar
No me queda claro si será mejor comprobar que (sum == 0) o contar directamente el número de rondas.

Ahi yo me cause una confusion tambien. Si se observa en C, sum es de 32 bits unsigned

Cuando se hace sum = XTEA_DELTA * num_round, se desplaza el dato a la derecha, 5 lugares para el caso de 32bits

Vos me diste este valor XTEA_DELTA 0x9E3779B9

Que si lo multiplico por 32 quedaria: 0x13C6EF3720, 1 byte mas. Pero luego cuando se guarda en sum, por ser de 32bits termino con
sum = 0xC6EF3720

Si resto continuamente ese valor siempre va a ser de 32bits, Por eso pienso que la condicion no debe ser sum = 0, lo pense en su momento para que contar las rondas si puedo esperar a 0, e incluso hice el ASM con sum de hasta 5 bytes. Pero luego me di cuenta que no es asi.

Tu ultimo codigo es justo, justo, identico, me copiaste, lo que estaba haciendo Picuino. xD

Código: ASM
  1. Loop_while
  2.  
  3.         RCALL   Termino
  4. ;Resta
  5.         SUB     sum[0],XTEA_DELTA[0]    ; sum -= XTEA_DELTA;
  6.         SBC     sum[1],XTEA_DELTA[1]
  7.         SBC     sum[2],XTEA_DELTA[2]
  8.         SBC     sum[3],XTEA_DELTA[3]
  9.  
  10. ;Cambio de lugar v0 y v1
  11.  
  12.         MOVW    Vtemp0[0],V1[0]
  13.         MOVW    Vtemp0[2],V1[2]
  14.         MOVW    V1[0],V0[0]
  15.         MOVW    V1[2],V0[2]
  16.         MOVW    V0[0],Vtemp0[0]
  17.         MOVW    V0[2],Vtemp0[2]
  18.  
  19.         RCALL   Termino
  20.  
  21. ;Cambio de lugar v0 y v1 , para la proxima ronda
  22.  
  23.         MOVW    Vtemp0[0],V1[0]
  24.         MOVW    Vtemp0[2],V1[2]
  25.         MOVW    V1[0],V0[0]
  26.         MOVW    V1[2],V0[2]
  27.         MOVW    V0[0],Vtemp0[0]
  28.         MOVW    V0[2],Vtemp0[2]
  29.  
  30.         DEC     Count
  31.         BRNE    Loop_while
  32.         RET
  33.  
  34.  
  35. Termino
  36.         LDI     ZL,0                    ; Recargo valor de Z con el valor original, para la proxima obtencion de valores de llaves.
  37.  
  38.         MOVW    Vtemp0[0],V0[0] ; Vtemp0 para (v0<<4) y Vtemp1 para (V0 >> 5)
  39.         MOVW    Vtemp0[2],V0[2]
  40.         MOVW    Vtemp1[0],V0[0]
  41.         MOVW    Vtemp1[2],V0[2]
  42.  
  43.         LDI     R0,4
  44. RotateLeftv0                    ; (v0 << 4)
  45.         LSL     Vtemp0[0]
  46.         ROL     Vtemp0[1]
  47.         ROL     Vtemp0[2]
  48.         ROL     Vtemp0[3]       ; Por ser de 32 bits se deberian perder los bits que salgan de aca
  49.         DEC     R0
  50.         BRNE    RotateLeftv0
  51.  
  52.         LDI     R0,5
  53. RotateRightv0                   ; (V0 >> 5 )
  54.         LSR     Vtemp1[3]
  55.         ROR     Vtemp1[2]
  56.         ROR     Vtemp1[1]
  57.         ROR     Vtemp1[0]
  58.         DEC     R0
  59.         BRNE    RotateRightv0
  60.  
  61.         EOR     Vtemp0[0],Vtemp1[0]     ;  (v0 << 4) ^ (v0 >> 5)
  62.         EOR     Vtemp0[1],Vtemp1[1]
  63.         EOR     Vtemp0[2],Vtemp1[2]
  64.         EOR     Vtemp0[3],Vtemp1[3]
  65.  
  66.         ADD     Vtemp0[0],V0[0]         ;  ((v0 << 4) ^ (v0 >> 5)) + v0
  67.         ADC     Vtemp0[1],V0[1]         ; Vtemp0 = ((v0 << 4) ^ (v0 >> 5)) + v0
  68.         ADC     Vtemp0[2],V0[2]
  69.         ADC     Vtemp0[3],V0[3]
  70.  
  71.         SBRS    Count,0
  72.         RJMP    Primer_t                ; Si es Par indica que es el primero. Si es impar es el segundo
  73. ;Seg_t
  74.         MOV     R0,sum[0]               ; sum & 3 , necesito multiplicarlo por 4, ya que son 4 bytes cada valor de llave
  75.         LSL     R0
  76.         LSL     R0
  77.         RJMP    Save_Sum
  78. Primer_t
  79.         MOV     R0,sum[1]               ; sum>>11 & 3 , 000a a000, 1 shift derecha, es igual a lo que se pide * 4
  80.         LSR     R0
  81. Save_Sum
  82.         ANDI    R0,0x0C                 ; 0000 aa00
  83.         ADD     ZL,R0                   ; Le sumo el valor de R0 o lo que es igual a 4 * index
  84.         LD      Vtemp1[0],Z+            ; key[sum&3] o key[(key>>11) & 3]
  85.         LD      Vtemp1[1],Z+
  86.         LD      Vtemp1[2],Z+
  87.         LD      Vtemp1[3],Z+
  88.  
  89.         ADD     Vtemp1[0],sum[0]        ; sum + key[(sum>>11) & 3]
  90.         ADC     Vtemp1[1],sum[1]        ; Aux = sum + key[(sum>>11) & 3]
  91.         ADC     Vtemp1[2],sum[2]
  92.         ADC     Vtemp1[3],sum[3]
  93.  
  94.         EOR     Vtemp0[0],Vtemp1[0]     ;  (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])
  95.         EOR     Vtemp0[1],Vtemp1[1]     ;   Vtemp[0]
  96.         EOR     Vtemp0[2],Vtemp1[2]
  97.         EOR     Vtemp0[3],Vtemp1[3]
  98.  
  99.         SUB     V1[0],Vtemp0[0]         ; v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])
  100.         SBC     V1[1],Vtemp0[1]
  101.         SBC     V1[2],Vtemp0[2]
  102.         SBC     V1[3],Vtemp0[3]         ; si ocurrio overflow ocurrio, lo lamento
  103.         RET

Me falta la parte de la inicializacion, en el que Z es a la base de Key
Paso de 105 lineas a 75, creo que podria reducirse en 3 lineas mas si hago el pasaje de V0 a V1 en un call.

Código: [Seleccionar]
R1  =
R2  =
R3  =
R4  =
R5  = Round
R6  = V1[0]
R7  = V1[1]
R8  = V1[2]
R9  = V1[3]
R10 = sum[0]
R11 = sum[1]
R12 = sum[2]
R13 = sum[3]
R14 = V0[0]
R15 = V0[1]
R16 = V0[2]
R17 = V0[3]
R18 = Vtemp0[0]
R19 = Vtemp0[1]
R20 = Vtemp0[2]
R21 = Vtemp0[3]
R22 = Vtemp1[0]
R23 = Vtemp1[1]
R24 = Vtemp1[2]
R25 = Vtemp1[3]
R26 = XL
R27 = XH
R28 = YL = SP
R29 = YH = SP
R30 = ZL
R31 = ZH

Como casi no utilizo la RAM podrias casi llenarla, esperar a decodificar todo y enviarle un mensaje al PC cuando este listo para recibir mas datos.
De la RAM necesito lugar para solo para los CALLs, cada CALL son 2bytes que es la direccion de retorno. Asi que para este codigo estara entre 3 a 4 CALLs como mucho. Inclusive el de llamada a desencriptarlo, unos 10bytes o por ahi cerca.
Hay 512 bytes. Asi que si haces bloques de 64bytes, podrias meter 7 bloques todo de una ocupandote 448 bytes y teniendo mucho espacio de RAM para el stack.

Si no era el problema el espacio, se podia pre-calcular sum, para cada vuelta. pero como el espacio apremia, entonces es preferible usar unas 10/20 instrucciones mas.
La otra es precalcularlo y guardarlo en una posicion especifica de la memoria, lo cual reduciria en 6 intrucciones el calculo de los terminos (lo cual haria mas rapido), pero agregaria mas instrucciones al inicio, por que hay que calcular todos los valores antes. Asi que estamos igual de mal sea la situacion que sea.

Mas compacto no se.. Intente usar las instrucciones que mejor se acomodaban para esto. Luego paso la inicializacion, Pero estoy mas que seguro que vas a terminar con unos 100 y algo de lineas.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 22 de Septiembre de 2015, 13:19:17
Muchas gracias Killer.
Yo creo que con eso ya está bien. Si en asm ocupa unos 250 bytes, por ahora es suficiente.
En c me ocupaba 250 bytes antes de empezar y se iva a 1k con el tratamiento por I2C, así que lo abandoné.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 22 de Septiembre de 2015, 14:35:23
Vos me diste este valor XTEA_DELTA 0x9E3779B9

Ese es el valor 'oficial'. Aparece en el código original. No sé si se podrá cambiar.

Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 22 de Septiembre de 2015, 14:36:26
Código optimizado:

Código: Python
  1. def xor_ta_tb():
  2.    global Ta, Tb
  3.    Ta ^= Tb
  4.  
  5.    
  6. def xtea_decode(data):
  7.    global Ta, Tb
  8.    data0 = data[0]
  9.    data1 = data[1]
  10.  
  11.    suma = 0xC6EF3720
  12.    rounds = 64
  13.    while(rounds):
  14.       Ta = data0
  15.       Tb = data1
  16.       data1 = Ta
  17.       data0 = Tb
  18.       Tb = Ta    
  19.       Ta <<= 4
  20.       Tb >>= 5
  21.       xor_ta_tb()
  22.       Ta += data1
  23.       if not (rounds & 1):
  24.          r1 = (suma>>11) & 3    
  25.       else:
  26.          r1 = suma & 3
  27.       Tb = xtea_key[r1]
  28.       Tb += suma
  29.       xor_ta_tb()
  30.       data0 -= Ta
  31.       data0 = uint32(data0)
  32.       if not (rounds & 1):
  33.          suma -= 0x9E3779B9
  34.          suma = uint32(suma)
  35.       rounds -= 1
  36.      
  37.    data[0] = data0
  38.    data[1] = data1
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 22 de Septiembre de 2015, 15:09:30
Te cuelgo mi ultima actualizacion Picuino, ya con un poco mas de codigo de AVR, segun el PDF "AVR Assembler User Guide"
Aunque le falta un poco de trabajo, ya note unas cosas que podria mejorar todavia, pero te hago las preguntas asi ya directamente hago todo de una sola ves

Código: ASM
  1. BUFF_SIZE               EQU     64      ; En bytes, y Multiplo de 8 debe ser
  2.  
  3. NUM_ROUND               EQU     32      ; Cantidad de Rondas
  4.  
  5. ADDRESS_BUFFER_HIGH     EQU     0x00    ; Direccion de base del buffer de datos, Solo si se usa direccion absoluta
  6. ADDRESS_BUFFER_LOW      EQU     0x00    ;
  7.  
  8. ADDRESS_KEY_HIGH        EQU     0x00    ; Direccion de base de llaves,
  9. ADDRESS_KEY_LOW         EQU     0x00    ; Unica restriccion: 0x00 <= ZL <= 0xC0
  10.  
  11. XTEA_DELTA[3]           EQU     0x9E    ; MSB
  12. XTEA_DELTA[2]           EQU     0x37    ; Si XTEA < (0x100000000 / NUM_ROUND) no se produce Overflow, para caso de 32
  13. XTEA_DELTA[1]           EQU     0x79    ; es XTEA < 0x8000000 o que es lo mismo que XTEA <= 0x7FFFFFF
  14. XTEA_DELTA[0]           EQU     0xB9
  15.  
  16. SUM[3]                  EQU     0xC6    ; MSB, Precalculado con XTEA_DELTA * NUM_ROUND
  17. SUM[2]                  EQU     0xEF    ; Hecho asi para ahorrar espacio en instrucciones
  18. SUM[1]                  EQU     0x37
  19. SUM[0]                  EQU     0x20
  20.  
  21.  
  22. .def Loop_Buff  = r4
  23. .def Round      = r5
  24. .def sum[0]     = r6
  25. .def sum[1]     = r7
  26. .def sum[2]     = r8
  27. .def sum[3]     = r9
  28. .def V0[0]      = r10
  29. .def V0[1]      = r11
  30. .def V0[2]      = r12
  31. .def V0[3]      = r13
  32. .def V1[0]      = r14
  33. .def V1[1]      = r15
  34. .def V1[2]      = r16
  35. .def V1[3]      = r17
  36. .def Vtemp0[0]  = r18
  37. .def Vtemp0[1]  = r19
  38. .def Vtemp0[2]  = r20
  39. .def Vtemp0[3]  = r21
  40. .def Vtemp1[0]  = r22
  41. .def Vtemp1[1]  = r23
  42. .def Vtemp1[2]  = r24
  43. .def Vtemp1[3]  = r25
  44. .def XL         = r26
  45. .def XH         = r27
  46. .def YL         = r28
  47. .def YH         = r29
  48. .def ZL         = r30
  49. .def ZH         = r31
  50.  
  51.  
  52.  
  53. ; Declaracion de espacio reservado en RAM para el Buffer, Aunque esto deberia haberse realizado antes con la UART
  54.  
  55. .DSEG
  56.  
  57.         Buffer: .BYTE   BUFF_SIZE
  58.  
  59. .CSEG
  60.  
  61.  
  62.  
  63. ; ******************************************************************************
  64. ;       XTAE_Init - Llamar antes de Iniciar la conversion, setea los punteros para el algortimo
  65. ;
  66. ;       Entradas:
  67. ;       ADDRES_KEY_* - CONST - Puntero a base de las llaves
  68. ;
  69. ;       Salidas:
  70. ;       -
  71. ;
  72. ;       Pre-Requisitos:
  73. ;       Haber creado una variable Buffer, y haberla llenado de datos.
  74. ;
  75. ; *****************************************************************************
  76.  
  77.  
  78.  
  79. XTEA_Init:
  80.  
  81.         LDI     YL,ADDRESS_BUFFER_LOW   ;       Y: Puntero de lectura/escritura, Y permite direccionamiento por offset
  82.         LDI     YH,ADDRESS_BUFFER_HIGH
  83.         LDI     ZH,ADDRESS_KEY_HIHG     ;       Z: Puntero a base de llave
  84.         LDI     ZL,ADDRESS_KEY_LOW
  85.  
  86. ;o, Aca hay que elegir si va a ser aboluta la direccion (arriba) o que lo maneje el linker (abajo)
  87.  
  88.         LDI     YL,low(Buffer)          ;       Y: Puntero de lectura/escritura, Y permite direccionamiento por offset
  89.         LDI     YH,high(Buffer)
  90.         LDI     ZH,ADDRESS_KEY_HIHG     ;       Z: Puntero a base de llave
  91.         LDI     ZL,ADDRESS_KEY_LOW
  92.         RET
  93.  
  94. ; ******************************************************************************
  95. ;       Decodificacion XTEA, desencripta con XTEA un bloque de BUFF_SIZE bytes
  96. ;
  97. ;       Entradas:
  98. ;       Y - Puntero a base del Buffer en la SRAM
  99. ;
  100. ;       Salidas:
  101. ;       Y -> Reescribe el buffer de BUFF_SIZE de entrada
  102. ;
  103. ;       Pre-Requisitos:
  104. ;       Valor Inicial SUM pre-calculado
  105. ;
  106. ; *****************************************************************************
  107.  
  108. XTEA_Dec:
  109.  
  110.         LDI     Loop_Buff,(BUFF_SIZE/8)         ;Recargamos el contador para saber cuando termino de recorrer el Buffer
  111.         LDI     sum[3],SUM[3]                   ;Recargamos el valor de suma ya pre-calculada.
  112.         LDI     sum[2],SUM[2]
  113.         LDI     sum[1],SUM[1]
  114.         LDI     sum[0],SUM[0]
  115.  
  116. XTEA_Dec_Aux:
  117.  
  118.         LDD     V0[0],Y+0       ; Cargo valores de V0
  119.         LDD     V0[1],Y+1
  120.         LDD     V0[2],Y+2
  121.         LDD     V0[3],Y+3
  122.  
  123.         LDD     V1[0],Y+4       ; Cargo valores de V1
  124.         LDD     V1[1],Y+5
  125.         LDD     V1[2],Y+6
  126.         LDD     V1[3],Y+7
  127.  
  128.         RCALL   Decodificacion  ; Decodificacion
  129.  
  130.         ST      Y+,V0[0]        ; Guardo los valores ya tratados
  131.         ST      Y+,V0[1]
  132.         ST      Y+,V0[2]
  133.         ST      Y+,V0[3]
  134.  
  135.         ST      Y+,V1[0]
  136.         ST      Y+,V1[1]
  137.         ST      Y+,V1[2]
  138.         ST      Y+,V1[3]        ; Me deja Y ya preparado para los proximos 8 bytes
  139.  
  140.         DEC     Loop_Buff
  141.         BRNE    XTEA_Dec_Aux
  142.         RET
  143.  
  144.  
  145. ; ******************************************************************************
  146. ;       Subrutina de XTEA_Dec, While en C, Realiza las NUM_ROUND sobre 8 bytes
  147. ;
  148. ;       Entradas:
  149. ;       V0[4] - 4 bytes del primer valor
  150. ;       v1[4] - 4 bytes del segundo valor
  151. ;       NUM_ROUND - CONST - Indica la cantidad de veces que se produce el arlgoritmo
  152. ;
  153. ;       Salidas:
  154. ;       Y -> Reescribe 8 bytes del Buffer de entrada
  155. ;
  156. ;       Pre-Requisitos:
  157. ;       -
  158. ;
  159. ; *****************************************************************************
  160.  
  161. Decodificacion:
  162.  
  163.         LDI     Count,(NUM_ROUND*2)
  164.  
  165. Loop_while_aux:
  166.  
  167.         RCALL   Termino
  168.  
  169.         SUB     sum[0],XTEA_DELTA[0]    ; sum -= XTEA_DELTA;
  170.         SBC     sum[1],XTEA_DELTA[1]
  171.         SBC     sum[2],XTEA_DELTA[2]
  172.         SBC     sum[3],XTEA_DELTA[3]
  173.  
  174.         MOVW    Vtemp0[0],V1[0]         ;Cambio de lugar v0 y v1
  175.         MOVW    Vtemp0[2],V1[2]
  176.         MOVW    V1[0],V0[0]
  177.         MOVW    V1[2],V0[2]
  178.         MOVW    V0[0],Vtemp0[0]
  179.         MOVW    V0[2],Vtemp0[2]
  180.  
  181.         RCALL   Termino
  182.  
  183.         MOVW    Vtemp0[0],V1[0]         ;Cambio de lugar v0 y v1 , para la proxima ronda, o para cuando hay que depositarlo
  184.         MOVW    Vtemp0[2],V1[2]
  185.         MOVW    V1[0],V0[0]
  186.         MOVW    V1[2],V0[2]
  187.         MOVW    V0[0],Vtemp0[0]
  188.         MOVW    V0[2],Vtemp0[2]
  189.  
  190.         DEC     Count
  191.         BRNE    Loop_while_aux
  192.         RET
  193.  
  194. ; ******************************************************************************
  195. ;       Subrutina de Decodificacion, procede a realizar lo siguiente:
  196. ;      
  197. ;       v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])       Para Count Par
  198. ;       v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[sum & 3])             Para Count Impar
  199. ;
  200. ;       Entradas:
  201. ;       V[4] - 4 bytes
  202. ;       Z - Puntero a base de las llaves en la SRAM
  203. ;       Count - Indicador de que ronda va
  204. ;
  205. ;       Salidas:
  206. ;       v[4] - 4 bytes
  207. ;
  208. ;       Pre-Requisitos:
  209. ;       -
  210. ;
  211. ; *****************************************************************************
  212.  
  213. Termino:
  214.         LDI     ZL,ADDRESS_KEY_LOW      ; Recargo valor de Z con el valor original, para el proximo termino, lo hago aca para ahorrar espacio, ademas al comienzo para que se mas facil verlo para cambiarlo
  215.  
  216.         MOVW    Vtemp0[0],V0[0] ; Vtemp0 para (v0<<4) y Vtemp1 para (V0 >> 5)
  217.         MOVW    Vtemp0[2],V0[2]
  218.         MOVW    Vtemp1[0],V0[0]
  219.         MOVW    Vtemp1[2],V0[2]
  220.  
  221.         LDI     R0,4
  222. RotateLeftv0:                   ; (v0 << 4)
  223.         LSL     Vtemp0[0]
  224.         ROL     Vtemp0[1]
  225.         ROL     Vtemp0[2]
  226.         ROL     Vtemp0[3]       ; Por ser de 32 bits se deberian perder los bits que salgan de aca
  227.         DEC     R0
  228.         BRNE    RotateLeftv0
  229.  
  230.         LDI     R0,5
  231. RotateRightv0:                  ; (V0 >> 5 )
  232.         LSR     Vtemp1[3]
  233.         ROR     Vtemp1[2]
  234.         ROR     Vtemp1[1]
  235.         ROR     Vtemp1[0]
  236.         DEC     R0
  237.         BRNE    RotateRightv0
  238.  
  239.         EOR     Vtemp0[0],Vtemp1[0]     ;  (v0 << 4) ^ (v0 >> 5)
  240.         EOR     Vtemp0[1],Vtemp1[1]
  241.         EOR     Vtemp0[2],Vtemp1[2]
  242.         EOR     Vtemp0[3],Vtemp1[3]
  243.  
  244.         ADD     Vtemp0[0],V0[0]         ;  ((v0 << 4) ^ (v0 >> 5)) + v0
  245.         ADC     Vtemp0[1],V0[1]         ; Vtemp0 = ((v0 << 4) ^ (v0 >> 5)) + v0
  246.         ADC     Vtemp0[2],V0[2]
  247.         ADC     Vtemp0[3],V0[3]
  248.  
  249.         SBRS    Count,0
  250.         RJMP    Primer_t                ; Si es Par indica que es el primero. Si es impar es el segundo
  251.  
  252.         MOV     R0,sum[0]               ; sum & 3
  253.         LSL     R0
  254.         LSL     R0
  255.         RJMP    Save_Sum
  256. Primer_t:
  257.         MOV     R0,sum[1]               ; sum>>11 & 3
  258.         LSR     R0
  259. Save_Sum:
  260.         ANDI    R0,0x0C                 ; 0000 aa00
  261.         ADD     ZL,R0                   ; Le sumo el valor de R0 o lo que es igual a 4 * index
  262.         LD      Vtemp1[0],Z+            ; key[sum&3] o key[(key>>11) & 3]
  263.         LD      Vtemp1[1],Z+
  264.         LD      Vtemp1[2],Z+
  265.         LD      Vtemp1[3],Z+
  266.  
  267.         ADD     Vtemp1[0],sum[0]        ; sum + key[(sum>>11) & 3]
  268.         ADC     Vtemp1[1],sum[1]        ; Aux = sum + key[(sum>>11) & 3]
  269.         ADC     Vtemp1[2],sum[2]
  270.         ADC     Vtemp1[3],sum[3]
  271.  
  272.         EOR     Vtemp0[0],Vtemp1[0]     ;  (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])
  273.         EOR     Vtemp0[1],Vtemp1[1]     ;   Vtemp[0]
  274.         EOR     Vtemp0[2],Vtemp1[2]
  275.         EOR     Vtemp0[3],Vtemp1[3]
  276.  
  277.         SUB     V1[0],Vtemp0[0]         ; v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])
  278.         SBC     V1[1],Vtemp0[1]
  279.         SBC     V1[2],Vtemp0[2]
  280.         SBC     V1[3],Vtemp0[3]         ; si ocurrio overflow, lo lamento
  281.         RET

Tengo una serie de preguntas mas por hacerte. Tanto a vos como a planeta que tiene mas experiencia.

1-
XTEA_DELTA si se puede seleccionar un valor tal que XTEA_DELTA <= 0x7FFFFFF
Ahi no se produciria un overflow, tendria que ver si es que realmente implica algo el que no exista ese ultimo byte, ya que si lo pensas en una resta a la sumo te queda el carry a restarle a la parte "superior", asi que se podria decir que no afectaria
Vos decidiras si es que deseas cambiarlo o no

2-
La llave donde va a ir? Memoria de programa, o RAM con unas "constantes" tal cual ves los EQU en el codigo?
Si es Memoria de programa debo cambiar algunas instrucciones (creo que achicando en 2 instrucciones), y tenes que pensar que van a ir 16 bytes mas en la FLASH
Si es la RAM, se debe agregar muchas mas instrucciones para inicializar esos datos en la RAM y poder tomarlos desde alli, no quitaria nada y agregaria unas 18 instrucciones
Velocidad vs Espacio

3-
Que tipo de direccionamiento queres? Podes elegir que el linker te "reserve" el espacio en la RAM y obtener la direccion con high(variable) y low(variable) o.. podes hacerlo con un direccionamiento absoluto a traves de los EQU
Si te fijas en XTEA_Init, hay 2 ejemplos, tengo que arreglarlo a eso para que quede 1 solo, y tambien lo de las llaves, Por eso cree un XTEA_Init, segun sea el caso que elijas de  estas preguntas, desapareceria esa funcion o no.
Definir el buffer lo deberias hacer con la UART (me refiero a lo de "reservar" el espacio de la RAM ), y directamente desde aca pedis la direccion de inicio para comenzar.

4-
Tenes pensado poner los valores de las llaves en algun valor de direccion en particular? se puede usar el .ORG para eso, y .DW para almacenar los valores en la FLASH , fijate que hay una restriccion asi como esta realizado el codigo sobre los valroes de direccion de las llaves, si lo queres para que este en cualquier posicion, entonces deberia agregar unas 2 instrucciones mas. Lo hice asi por el espacio :/

5-
Debo salvar algun registro a la pila por algun valor que estes utilizando ?
Por que no se me ocurre alguno, tal ves el de Z, o Y, que son los punteros, pero no creo que los necesites ya que una ves que pasas la decodificacion, fue por que recibiste todo.

6-
Vas a crear solamente 1 Buffer de 64 bytes o mas?, Si tenes pensado crear 4 buffer solo cambia el valor de BUFFER_SIZE a 4*64 , Solo prestar atencion que debe ser multiplo de 8

7-
Como estan guardados los datos? Ya que de tomarlo de otra punta terminaria mal, esto para acomodar cuando los cargo/grabo a la RAM.
Ejemplo, los pimeros 8 bytes 0x12345678  0x12345678

Guardados asi:
0x12 0x34 0x56 0x78 0x12 0x34 0x56 0x78

o asi:
0x78 0x56 0x34 0x12 0x78 0x56 0x34 0x12

Esto va a depender de tu UART y cmo los envies

8-
Tenes idea si se permiten los corchetes en los nombres? Yo lo hize asi por que era mas facil para mi darme cuenta


Resuelta estas dudas creo que termino el codigo, Aunque sin probarlo :/
Y ya reviso tu codigo haber si me das una mejor idea o si es lo mismo realizado en ASM
Título: Re: Bootloader encriptado para Attiny88
Publicado por: juaperser1 en 22 de Septiembre de 2015, 16:19:14
Solo quiero decir que estoy siguiendo el hilo, no contribuyo por que no entiendo del tema, pero sigo muy atento a los avances  ;-) pronto migraré de microchip y todas estas cosas me ayudarán a decidirme por una marca u otra.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 22 de Septiembre de 2015, 18:20:34
1-
XTEA_DELTA si se puede seleccionar un valor tal que XTEA_DELTA <= 0x7FFFFFF
Ahi no se produciria un overflow, tendria que ver si es que realmente implica algo el que no exista ese ultimo byte, ya que si lo pensas en una resta a la sumo te queda el carry a restarle a la parte "superior", asi que se podria decir que no afectaria
Vos decidiras si es que deseas cambiarlo o no
Yo creo que ese valor es fijo y no se puede cambiar. Forma parte de la rutina de encriptación.

2-
La llave donde va a ir? Memoria de programa, o RAM con unas "constantes" tal cual ves los EQU en el codigo?
Si es Memoria de programa debo cambiar algunas instrucciones (creo que achicando en 2 instrucciones), y tenes que pensar que van a ir 16 bytes mas en la FLASH
Si es la RAM, se debe agregar muchas mas instrucciones para inicializar esos datos en la RAM y poder tomarlos desde alli, no quitaria nada y agregaria unas 18 instrucciones
Velocidad vs Espacio
Yo estoy intentando ponerla en la memoria de programa (flash) y leerla con el puntero Z. Creo que es lo más sencillo y pequeño.


3-
Que tipo de direccionamiento queres? Podes elegir que el linker te "reserve" el espacio en la RAM y obtener la direccion con high(variable) y low(variable) o.. podes hacerlo con un direccionamiento absoluto a traves de los EQU
Si te fijas en XTEA_Init, hay 2 ejemplos, tengo que arreglarlo a eso para que quede 1 solo, y tambien lo de las llaves, Por eso cree un XTEA_Init, segun sea el caso que elijas de  estas preguntas, desapareceria esa funcion o no.
Definir el buffer lo deberias hacer con la UART (me refiero a lo de "reservar" el espacio de la RAM ), y directamente desde aca pedis la direccion de inicio para comenzar.
Lo mejor es ponerlo a mano para poder controlar bien la memoria. Tampoco es muy complicado el programa.


4-
Tenes pensado poner los valores de las llaves en algun valor de direccion en particular? se puede usar el .ORG para eso, y .DW para almacenar los valores en la FLASH , fijate que hay una restriccion asi como esta realizado el codigo sobre los valroes de direccion de las llaves, si lo queres para que este en cualquier posicion, entonces deberia agregar unas 2 instrucciones mas. Lo hice asi por el espacio :/
Quiero poner todo al final de la memoria. Se puede inicializar Z = dirección de la llave + r1*4 y luego leer con "LMP   temp0, Z+"


5-
Debo salvar algun registro a la pila por algun valor que estes utilizando ?
Por que no se me ocurre alguno, tal ves el de Z, o Y, que son los punteros, pero no creo que los necesites ya que una ves que pasas la decodificacion, fue por que recibiste todo.
Lo mejor es que el bootloader guarde sus variables antes del rcall.


6-
Vas a crear solamente 1 Buffer de 64 bytes o mas?, Si tenes pensado crear 4 buffer solo cambia el valor de BUFFER_SIZE a 4*64 , Solo prestar atencion que debe ser multiplo de 8
Sólo un buffer de 64 bytes por ahora. Es el tamaño de página de la Flash para escritura. No necesito más.


7-
Como estan guardados los datos? Ya que de tomarlo de otra punta terminaria mal, esto para acomodar cuando los cargo/grabo a la RAM.
Ejemplo, los pimeros 8 bytes 0x12345678  0x12345678

Guardados asi:
0x12 0x34 0x56 0x78 0x12 0x34 0x56 0x78

o asi:
0x78 0x56 0x34 0x12 0x78 0x56 0x34 0x12

Esto va a depender de tu UART y cmo los envies
Voy a utilizar la notación little-endian, que es la del Attiny. Primero el byte menos significativo. Byte menos significativo en posiciones más bajas (primera opción).

8-
Tenes idea si se permiten los corchetes en los nombres? Yo lo hize asi por que era mas facil para mi darme cuenta
No lo sé.


Otro problema que he notado es que no se pueden enviar todas las posiciones de memoria encriptadas.
Si se envían varios bloques de 4bytes todos a cero (o todos con 0xFF), se va a notar porque el archivo encriptado tendrá bloques de 4 bytes iguales. A partir de esto es posible iniciar un ataque.
La complejidad de la llave se puede reducir en 32 bits.

El autor recomienda hacer una encriptación de todo un bloque (64 bytes), pero es más compleja.

Otra solución es enviar paquetes de datos de tamaño variable y eliminar los huecos a cero. Complica un poco el bootloader, pero da mayor seguridad.


Estoy peleándome con el ensamblador para eliminar los fallos. Me estoy fijando en tu código para conseguirlo. Cuando lo tenga lo posteo.
Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 22 de Septiembre de 2015, 18:42:29
AVR Assembler User Guide:
http://www.atmel.com/Images/doc1022.pdf

Creo que está escrito para el compilador de Atmel. Me gustaría utilizar el ensamblador GNU, pero no hay apenas documentación.


Manual del ensamblador GNU:
https://sourceware.org/binutils/docs/as/
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 22 de Septiembre de 2015, 19:20:03
Ya veo lo del compilador GNU Picuino.

Citar
Quiero poner todo al final de la memoria. Se puede inicializar Z = dirección de la llave + r1*4 y luego leer con "LMP   temp0, Z+"

No lo decia por eso es que el codigo que habia pasado practicamente habia realizado la suma del valor del registro con la parte baja de Z, pero no traslade eso a la parte superior, por eso preguntaba si ibas a ponerlo en un algun lado en especial. Sino ya lo arregle agregando 2 lineas como te habia dicho, permitiendo que cualquier cosa que ocurra y la key se encuentre en una posicion comprometida no afecte al programa.

Citar
Yo creo que ese valor es fijo y no se puede cambiar. Forma parte de la rutina de encriptación.

Busque y en un paper que hablaba sobre XTEA, decia que uno debia elegir la llave Y el valor del delta. Por que dejando fijo el valor del delta estas practicamente entregando la mitad del codigo, mas cuando es sacado de wikipedia :P
Y sino habria que probar si es que encriptando y desencriptando con otro delta no produce los resultados que uno espera.

Citar
Otro problema que he notado es que no se pueden enviar todas las posiciones de memoria encriptadas.
Si se envían varios bloques de 4bytes todos a cero (o todos con 0xFF), se va a notar porque el archivo encriptado tendrá bloques de 4 bytes iguales. A partir de esto es posible iniciar un ataque.
La complejidad de la llave se puede reducir en 32 bits.

Y cual es el problema ? llenalos de valores random si no te da multiplo de 64 bytes, si total ahi no deberia llegar NUNCA

--------------------------------------

Despues de todo se me ocurrio otro problema, mas que un problema una situacion.

Por ejemplo, en el caso que la otra persona se ponga a meter mano y "borre" el bootloader, como te vas a enfrentar a eso?
Por que esto sirve muy bien como para una "actualizacion" pero cuando se borra completamente todo, te vas a enfrentar con el tema de que hay que cargarle el firmware completo. Y esto ya no se puede hacer mas encriptado.


---------------------------------------

Nuevamente creo que termine el mio, solo me faltaria acomodarlo para GNU

Código: ASM
  1. .EQU    BUFF_SIZE               = 64    ; En bytes, y Multiplo de 8 debe ser
  2.  
  3. .EQU    NUM_ROUND               = 32    ; Cantidad de Rondas
  4.  
  5. .EQU    ADDRESS_BUFFER_HIGH     = 0x10  ; Direccion de base del buffer de datos, Solo si se usa direccion absoluta
  6. .EQU    ADDRESS_BUFFER_LOW      = 0x00  ; Recordar que debe sere mayor a 0x1000 la direccion
  7.  
  8. .EQU    XTEA_DELTA[3]           = 0x9E  ; MSB
  9. .EQU    XTEA_DELTA[2]           = 0x37  ;
  10. .EQU    XTEA_DELTA[1]           = 0x79  ;
  11. .EQU    XTEA_DELTA[0]           = 0xB9
  12.  
  13. .EQU    SUM[3]                  = 0xC6  ; MSB, Precalculado con XTEA_DELTA * NUM_ROUND
  14. .EQU    SUM[2]                  = 0xEF  ; Hecho asi para ahorrar espacio en instrucciones
  15. .EQU    SUM[1]                  = 0x37
  16. .EQU    SUM[0]                  = 0x20
  17.  
  18.  
  19. .def Loop_Buff  = r4
  20. .def Round      = r5
  21. .def sum[0]     = r6
  22. .def sum[1]     = r7
  23. .def sum[2]     = r8
  24. .def sum[3]     = r9
  25. .def V0[0]      = r10
  26. .def V0[1]      = r11
  27. .def V0[2]      = r12
  28. .def V0[3]      = r13
  29. .def V1[0]      = r14
  30. .def V1[1]      = r15
  31. .def V1[2]      = r16
  32. .def V1[3]      = r17
  33. .def Vtemp0[0]  = r18
  34. .def Vtemp0[1]  = r19
  35. .def Vtemp0[2]  = r20
  36. .def Vtemp0[3]  = r21
  37. .def Vtemp1[0]  = r22
  38. .def Vtemp1[1]  = r23
  39. .def Vtemp1[2]  = r24
  40. .def Vtemp1[3]  = r25
  41. .def XL         = r26
  42. .def XH         = r27
  43. .def YL         = r28
  44. .def YH         = r29
  45. .def ZL         = r30
  46. .def ZH         = r31
  47.  
  48.  
  49.  
  50. ; Inicializacion de llaves en Flash
  51. Keys:   .DW     0x1234, 0x5678          ; [0]
  52.         .DW     0x1234, 0x5678          ; [1]
  53.         .DW     0x1234, 0x5678          ; [2]
  54.         .DW     0x1234, 0x5678          ; [3]
  55.  
  56.  
  57. ; ******************************************************************************
  58. ;       Decodificacion XTEA, desencripta con XTEA un bloque de BUFF_SIZE bytes
  59. ;
  60. ;       Entradas:
  61. ;       Y - Puntero a base del Buffer en la SRAM
  62. ;
  63. ;       Salidas:
  64. ;       Y -> Reescribe el buffer de BUFF_SIZE de entrada
  65. ;
  66. ;       Pre-Requisitos:
  67. ;       Valor Inicial SUM pre-calculado
  68. ;
  69. ;
  70. ;       Registros usados:
  71. ;       R0, R4-R25 , R28-R31
  72. ;
  73. ; *****************************************************************************
  74.  
  75. XTEA_Dec:
  76.  
  77.         LDI     YL,ADDRESS_BUFFER_LOW   ;       Y: Puntero de lectura/escritura, Y permite direccionamiento por offset
  78.         LDI     YH,ADDRESS_BUFFER_HIGH
  79.  
  80.         LDI     Loop_Buff,(BUFF_SIZE/8)         ;Recargamos el contador para saber cuando termino de recorrer el Buffer
  81.         LDI     sum[3],SUM[3]                   ;Recargamos el valor de suma ya pre-calculada.
  82.         LDI     sum[2],SUM[2]
  83.         LDI     sum[1],SUM[1]
  84.         LDI     sum[0],SUM[0]
  85.  
  86. XTEA_Dec_Aux:
  87.  
  88.         ; Carga realizada en Little Endian
  89.  
  90.         LDD     V0[0],Y+0       ; Cargo valores de V0
  91.         LDD     V0[1],Y+1
  92.         LDD     V0[2],Y+2
  93.         LDD     V0[3],Y+3
  94.  
  95.         LDD     V1[0],Y+4       ; Cargo valores de V1
  96.         LDD     V1[1],Y+5
  97.         LDD     V1[2],Y+6
  98.         LDD     V1[3],Y+7
  99.  
  100.         RCALL   Decodificacion  ; Decodificacion
  101.  
  102.         ST      Y+,V0[0]        ; Guardo los valores ya tratados
  103.         ST      Y+,V0[1]
  104.         ST      Y+,V0[2]
  105.         ST      Y+,V0[3]
  106.  
  107.         ST      Y+,V1[0]
  108.         ST      Y+,V1[1]
  109.         ST      Y+,V1[2]
  110.         ST      Y+,V1[3]        ; Me deja Y ya preparado para los proximos 8 bytes
  111.  
  112.         DEC     Loop_Buff
  113.         BRNE    XTEA_Dec_Aux
  114.         RET
  115.  
  116.  
  117. ; ******************************************************************************
  118. ;       Subrutina de XTEA_Dec, While en C, Realiza las NUM_ROUND sobre 8 bytes
  119. ;
  120. ;       Entradas:
  121. ;       V0[4] - 4 bytes del primer valor
  122. ;       v1[4] - 4 bytes del segundo valor
  123. ;       NUM_ROUND - CONST - Indica la cantidad de veces que se produce el arlgoritmo
  124. ;
  125. ;       Salidas:
  126. ;       Y -> Reescribe 8 bytes del Buffer de entrada
  127. ;
  128. ;       Pre-Requisitos:
  129. ;       -
  130. ;
  131. ; *****************************************************************************
  132.  
  133. Decodificacion:
  134.  
  135.         LDI     Count,(NUM_ROUND*2)
  136.  
  137. Loop_while_aux:
  138.  
  139.         RCALL   Termino
  140.  
  141.         SUB     sum[0],XTEA_DELTA[0]    ; sum -= XTEA_DELTA;
  142.         SBC     sum[1],XTEA_DELTA[1]
  143.         SBC     sum[2],XTEA_DELTA[2]
  144.         SBC     sum[3],XTEA_DELTA[3]
  145.  
  146.         MOVW    Vtemp0[0],V1[0]         ;Cambio de lugar v0 y v1
  147.         MOVW    Vtemp0[2],V1[2]
  148.         MOVW    V1[0],V0[0]
  149.         MOVW    V1[2],V0[2]
  150.         MOVW    V0[0],Vtemp0[0]
  151.         MOVW    V0[2],Vtemp0[2]
  152.  
  153.         RCALL   Termino
  154.  
  155.         MOVW    Vtemp0[0],V1[0]         ;Cambio de lugar v0 y v1 , para la proxima ronda, o para cuando hay que depositarlo
  156.         MOVW    Vtemp0[2],V1[2]
  157.         MOVW    V1[0],V0[0]
  158.         MOVW    V1[2],V0[2]
  159.         MOVW    V0[0],Vtemp0[0]
  160.         MOVW    V0[2],Vtemp0[2]
  161.  
  162.         DEC     Count
  163.         BRNE    Loop_while_aux
  164.         RET
  165.  
  166. ; ******************************************************************************
  167. ;       Subrutina de Decodificacion, procede a realizar lo siguiente:
  168. ;      
  169. ;       v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])       Para Count Par
  170. ;       v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[sum & 3])             Para Count Impar
  171. ;
  172. ;       Entradas:
  173. ;       V[4] - 4 bytes
  174. ;       Z - Puntero a base de las llaves en la SRAM
  175. ;       Count - Indicador de que ronda va
  176. ;
  177. ;       Salidas:
  178. ;       v[4] - 4 bytes
  179. ;
  180. ;       Pre-Requisitos:
  181. ;       -
  182. ;
  183. ; *****************************************************************************
  184.  
  185. Termino:
  186.         LDI     ZH,high(Keys)   ; Recargo valor de Z, por que lo modifique anteriormente
  187.         LDI     ZL,low(Keys)
  188.  
  189.         MOVW    Vtemp0[0],V0[0] ; Vtemp0 para (v0<<4) y Vtemp1 para (V0 >> 5)
  190.         MOVW    Vtemp0[2],V0[2]
  191.         MOVW    Vtemp1[0],V0[0]
  192.         MOVW    Vtemp1[2],V0[2]
  193.  
  194.         LDI     R0,4
  195. RotateLeftv0:                   ; (v0 << 4)
  196.         LSL     Vtemp0[0]
  197.         ROL     Vtemp0[1]
  198.         ROL     Vtemp0[2]
  199.         ROL     Vtemp0[3]       ; Por ser de 32 bits se deberian perder los bits que salgan de aca
  200.         DEC     R0
  201.         BRNE    RotateLeftv0
  202.  
  203.         LDI     R0,5
  204. RotateRightv0:                  ; (V0 >> 5 )
  205.         LSR     Vtemp1[3]
  206.         ROR     Vtemp1[2]
  207.         ROR     Vtemp1[1]
  208.         ROR     Vtemp1[0]
  209.         DEC     R0
  210.         BRNE    RotateRightv0
  211.  
  212.         EOR     Vtemp0[0],Vtemp1[0]     ;  (v0 << 4) ^ (v0 >> 5)
  213.         EOR     Vtemp0[1],Vtemp1[1]
  214.         EOR     Vtemp0[2],Vtemp1[2]
  215.         EOR     Vtemp0[3],Vtemp1[3]
  216.  
  217.         ADD     Vtemp0[0],V0[0]         ;  ((v0 << 4) ^ (v0 >> 5)) + v0
  218.         ADC     Vtemp0[1],V0[1]         ; Vtemp0 = ((v0 << 4) ^ (v0 >> 5)) + v0
  219.         ADC     Vtemp0[2],V0[2]
  220.         ADC     Vtemp0[3],V0[3]
  221.  
  222.         SBRS    Count,0
  223.         RJMP    Primer_t                ; Si es Par indica que es el primero. Si es impar es el segundo
  224.  
  225.         MOV     R0,sum[0]               ; sum & 3
  226.         LSL     R0
  227.         LSL     R0
  228.         RJMP    Save_Sum
  229. Primer_t:
  230.         MOV     R0,sum[1]               ; sum>>11 & 3
  231.         LSR     R0
  232. Save_Sum:
  233.         ANDI    R0,0x0C                 ; 0000 aa00
  234.         ADD     ZL,R0                   ; Le sumo el valor de R0 o lo que es igual a 4 * index
  235.         CLR     R0                      ; Me aseguro que por mas que caiga donde sea la llave en el programa no se produzca algun error
  236.         ADC     ZH,R0                   ; Sumandole el carry
  237.         LPM     Vtemp1[0],Z+            ; key[sum&3] o key[(key>>11) & 3]
  238.         LPM     Vtemp1[1],Z+
  239.         LPM     Vtemp1[2],Z+
  240.         LPM     Vtemp1[3],Z+
  241.  
  242.         ADD     Vtemp1[0],sum[0]        ; sum + key[(sum>>11) & 3]
  243.         ADC     Vtemp1[1],sum[1]        ; Aux = sum + key[(sum>>11) & 3]
  244.         ADC     Vtemp1[2],sum[2]
  245.         ADC     Vtemp1[3],sum[3]
  246.  
  247.         EOR     Vtemp0[0],Vtemp1[0]     ;  (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])
  248.         EOR     Vtemp0[1],Vtemp1[1]     ;   Vtemp[0]
  249.         EOR     Vtemp0[2],Vtemp1[2]
  250.         EOR     Vtemp0[3],Vtemp1[3]
  251.  
  252.         SUB     V1[0],Vtemp0[0]         ; v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])
  253.         SBC     V1[1],Vtemp0[1]
  254.         SBC     V1[2],Vtemp0[2]
  255.         SBC     V1[3],Vtemp0[3]         ; si ocurrio overflow, lo lamento
  256.         RET

GNU, creo que no requirio tanto cambio:

Código: ASM
  1. ; Constantes
  2.  
  3.  
  4. .EQU    BUFF_SIZE               , 64    ; En bytes, y Multiplo de 8 debe ser
  5.  
  6. .EQU    NUM_ROUND               , 32    ; Cantidad de Rondas
  7.  
  8. .EQU    ADDRESS_BUFFER_HIGH     , 0x10  ; Direccion de base del buffer de datos, Solo si se usa direccion absoluta
  9. .EQU    ADDRESS_BUFFER_LOW      , 0x00  ; Recordar que debe sere mayor a 0x1000 la direccion
  10.  
  11. .EQU    XTEA_DELTA[3]           , 0x9E  ; MSB
  12. .EQU    XTEA_DELTA[2]           , 0x37  ;
  13. .EQU    XTEA_DELTA[1]           , 0x79  ;
  14. .EQU    XTEA_DELTA[0]           , 0xB9
  15.  
  16. .EQU    SUM[3]                  , 0xC6  ; MSB, Precalculado con XTEA_DELTA * NUM_ROUND
  17. .EQU    SUM[2]                  , 0xEF  ; Hecho asi para ahorrar espacio en instrucciones
  18. .EQU    SUM[1]                  , 0x37
  19. .EQU    SUM[0]                  , 0x20
  20.  
  21.  
  22.  
  23. ; Registros
  24.  
  25. .def Loop_Buff  , r4
  26. .def Round      , r5
  27. .def sum[0]     , r6
  28. .def sum[1]     , r7
  29. .def sum[2]     , r8
  30. .def sum[3]     , r9
  31. .def V0[0]      , r10
  32. .def V0[1]      , r11
  33. .def V0[2]      , r12
  34. .def V0[3]      , r13
  35. .def V1[0]      , r14
  36. .def V1[1]      , r15
  37. .def V1[2]      , r16
  38. .def V1[3]      , r17
  39. .def Vtemp0[0]  , r18
  40. .def Vtemp0[1]  , r19
  41. .def Vtemp0[2]  , r20
  42. .def Vtemp0[3]  , r21
  43. .def Vtemp1[0]  , r22
  44. .def Vtemp1[1]  , r23
  45. .def Vtemp1[2]  , r24
  46. .def Vtemp1[3]  , r25
  47. .def XL         , r26
  48. .def XH         , r27
  49. .def YL         , r28
  50. .def YH         , r29
  51. .def ZL         , r30
  52. .def ZH         , r31
  53.  
  54.  
  55. ; Seccion, para acomodar en el linker
  56.  
  57. .section bootloader
  58.  
  59. ; Inicializacion de llaves en Flash
  60.  
  61. Keys:   .hword  0x1234, 0x5678          ; [0]
  62.         .hword  0x1234, 0x5678          ; [1]
  63.         .hword  0x1234, 0x5678          ; [2]
  64.         .hword  0x1234, 0x5678          ; [3]
  65.  
  66.  
  67. ; ******************************************************************************
  68. ;       Decodificacion XTEA, desencripta con XTEA un bloque de BUFF_SIZE bytes
  69. ;
  70. ;       Entradas:
  71. ;       Y - Puntero a base del Buffer en la SRAM
  72. ;
  73. ;       Salidas:
  74. ;       Y -> Reescribe el buffer de BUFF_SIZE de entrada
  75. ;
  76. ;       Pre-Requisitos:
  77. ;       Valor Inicial SUM pre-calculado
  78. ;
  79. ;
  80. ;       Registros usados:
  81. ;       R0, R4-R25 , R28-R31
  82. ;
  83. ; *****************************************************************************
  84.  
  85. XTEA_Dec:
  86.  
  87.         LDI     YL,ADDRESS_BUFFER_LOW           ;       Y: Puntero de lectura/escritura, Y permite direccionamiento por offset
  88.         LDI     YH,ADDRESS_BUFFER_HIGH
  89.  
  90.         LDI     Loop_Buff,(BUFF_SIZE/8)         ;Recargamos el contador para saber cuando termino de recorrer el Buffer
  91.         LDI     sum[3],SUM[3]                   ;Recargamos el valor de suma ya pre-calculada.
  92.         LDI     sum[2],SUM[2]
  93.         LDI     sum[1],SUM[1]
  94.         LDI     sum[0],SUM[0]
  95.  
  96. XTEA_Dec_Aux:
  97.  
  98.         ; Carga realizada en Little Endian
  99.  
  100.         LDD     V0[0],Y+0       ; Cargo valores de V0
  101.         LDD     V0[1],Y+1
  102.         LDD     V0[2],Y+2
  103.         LDD     V0[3],Y+3
  104.  
  105.         LDD     V1[0],Y+4       ; Cargo valores de V1
  106.         LDD     V1[1],Y+5
  107.         LDD     V1[2],Y+6
  108.         LDD     V1[3],Y+7
  109.  
  110.         RCALL   Decodificacion  ; Decodificacion
  111.  
  112.         ST      Y+,V0[0]        ; Guardo los valores ya tratados
  113.         ST      Y+,V0[1]
  114.         ST      Y+,V0[2]
  115.         ST      Y+,V0[3]
  116.  
  117.         ST      Y+,V1[0]
  118.         ST      Y+,V1[1]
  119.         ST      Y+,V1[2]
  120.         ST      Y+,V1[3]        ; Me deja Y ya preparado para los proximos 8 bytes
  121.  
  122.         DEC     Loop_Buff
  123.         BRNE    XTEA_Dec_Aux
  124.         RET
  125.  
  126.  
  127. ; ******************************************************************************
  128. ;       Subrutina de XTEA_Dec, While en C, Realiza las NUM_ROUND sobre 8 bytes
  129. ;
  130. ;       Entradas:
  131. ;       V0[4] - 4 bytes del primer valor
  132. ;       v1[4] - 4 bytes del segundo valor
  133. ;       NUM_ROUND - CONST - Indica la cantidad de veces que se produce el arlgoritmo
  134. ;
  135. ;       Salidas:
  136. ;       Y -> Reescribe 8 bytes del Buffer de entrada
  137. ;
  138. ;       Pre-Requisitos:
  139. ;       -
  140. ;
  141. ; *****************************************************************************
  142.  
  143. Decodificacion:
  144.  
  145.         LDI     Count,(NUM_ROUND*2)
  146.  
  147. Loop_while_aux:
  148.  
  149.         RCALL   Termino
  150.  
  151.         SUB     sum[0],XTEA_DELTA[0]    ; sum -= XTEA_DELTA;
  152.         SBC     sum[1],XTEA_DELTA[1]
  153.         SBC     sum[2],XTEA_DELTA[2]
  154.         SBC     sum[3],XTEA_DELTA[3]
  155.  
  156.         MOVW    Vtemp0[0],V1[0]         ;Cambio de lugar v0 y v1
  157.         MOVW    Vtemp0[2],V1[2]
  158.         MOVW    V1[0],V0[0]
  159.         MOVW    V1[2],V0[2]
  160.         MOVW    V0[0],Vtemp0[0]
  161.         MOVW    V0[2],Vtemp0[2]
  162.  
  163.         RCALL   Termino
  164.  
  165.         MOVW    Vtemp0[0],V1[0]         ;Cambio de lugar v0 y v1 , para la proxima ronda, o para cuando hay que depositarlo
  166.         MOVW    Vtemp0[2],V1[2]
  167.         MOVW    V1[0],V0[0]
  168.         MOVW    V1[2],V0[2]
  169.         MOVW    V0[0],Vtemp0[0]
  170.         MOVW    V0[2],Vtemp0[2]
  171.  
  172.         DEC     Count
  173.         BRNE    Loop_while_aux
  174.         RET
  175.  
  176. ; ******************************************************************************
  177. ;       Subrutina de Decodificacion, procede a realizar lo siguiente:
  178. ;      
  179. ;       v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])       Para Count Par
  180. ;       v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[sum & 3])             Para Count Impar
  181. ;
  182. ;       Entradas:
  183. ;       V[4] - 4 bytes
  184. ;       Z - Puntero a base de las llaves en la SRAM
  185. ;       Count - Indicador de que ronda va
  186. ;
  187. ;       Salidas:
  188. ;       v[4] - 4 bytes
  189. ;
  190. ;       Pre-Requisitos:
  191. ;       -
  192. ;
  193. ; *****************************************************************************
  194.  
  195. Termino:
  196.         LDI     ZH,pm_hi8(Keys) ; Recargo valor de Z, por que lo modifique anteriormente
  197.         LDI     ZL,pm_lo8(Keys)
  198.  
  199.         MOVW    Vtemp0[0],V0[0] ; Vtemp0 para (v0<<4) y Vtemp1 para (V0 >> 5)
  200.         MOVW    Vtemp0[2],V0[2]
  201.         MOVW    Vtemp1[0],V0[0]
  202.         MOVW    Vtemp1[2],V0[2]
  203.  
  204.         LDI     R0,4
  205. RotateLeftv0:                   ; (v0 << 4)
  206.         LSL     Vtemp0[0]
  207.         ROL     Vtemp0[1]
  208.         ROL     Vtemp0[2]
  209.         ROL     Vtemp0[3]       ; Por ser de 32 bits se deberian perder los bits que salgan de aca
  210.         DEC     R0
  211.         BRNE    RotateLeftv0
  212.  
  213.         LDI     R0,5
  214. RotateRightv0:                  ; (V0 >> 5 )
  215.         LSR     Vtemp1[3]
  216.         ROR     Vtemp1[2]
  217.         ROR     Vtemp1[1]
  218.         ROR     Vtemp1[0]
  219.         DEC     R0
  220.         BRNE    RotateRightv0
  221.  
  222.         EOR     Vtemp0[0],Vtemp1[0]     ;  (v0 << 4) ^ (v0 >> 5)
  223.         EOR     Vtemp0[1],Vtemp1[1]
  224.         EOR     Vtemp0[2],Vtemp1[2]
  225.         EOR     Vtemp0[3],Vtemp1[3]
  226.  
  227.         ADD     Vtemp0[0],V0[0]         ;  ((v0 << 4) ^ (v0 >> 5)) + v0
  228.         ADC     Vtemp0[1],V0[1]         ; Vtemp0 = ((v0 << 4) ^ (v0 >> 5)) + v0
  229.         ADC     Vtemp0[2],V0[2]
  230.         ADC     Vtemp0[3],V0[3]
  231.  
  232.         SBRS    Count,0
  233.         RJMP    Primer_t                ; Si es Par indica que es el primero. Si es impar es el segundo
  234.  
  235.         MOV     R0,sum[0]               ; sum & 3
  236.         LSL     R0
  237.         LSL     R0
  238.         RJMP    Save_Sum
  239. Primer_t:
  240.         MOV     R0,sum[1]               ; sum>>11 & 3
  241.         LSR     R0
  242. Save_Sum:
  243.         ANDI    R0,0x0C                 ; 0000 aa00
  244.         ADD     ZL,R0                   ; Le sumo el valor de R0 o lo que es igual a 4 * index
  245.         CLR     R0                      ; Me aseguro que por mas que caiga donde sea la llave en el programa no se produzca algun error
  246.         ADC     ZH,R0                   ; Sumandole el carry
  247.         LPM     Vtemp1[0],Z+            ; key[sum&3] o key[(key>>11) & 3]
  248.         LPM     Vtemp1[1],Z+
  249.         LPM     Vtemp1[2],Z+
  250.         LPM     Vtemp1[3],Z+
  251.  
  252.         ADD     Vtemp1[0],sum[0]        ; sum + key[(sum>>11) & 3]
  253.         ADC     Vtemp1[1],sum[1]        ; Aux = sum + key[(sum>>11) & 3]
  254.         ADC     Vtemp1[2],sum[2]
  255.         ADC     Vtemp1[3],sum[3]
  256.  
  257.         EOR     Vtemp0[0],Vtemp1[0]     ;  (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])
  258.         EOR     Vtemp0[1],Vtemp1[1]     ;   Vtemp[0]
  259.         EOR     Vtemp0[2],Vtemp1[2]
  260.         EOR     Vtemp0[3],Vtemp1[3]
  261.  
  262.         SUB     V1[0],Vtemp0[0]         ; v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])
  263.         SBC     V1[1],Vtemp0[1]
  264.         SBC     V1[2],Vtemp0[2]
  265.         SBC     V1[3],Vtemp0[3]         ; si ocurrio overflow, lo lamento
  266.         RET

.equ xx,xx
.def xx,xx

agregue un:

.section bootloader

Aunque eso lo debes hacer en todo el bootloader

Cambie los high() y low() por los pm_hi8() y pm_lo8() , que es lo mismo que hi8() y lo8() nomas que tenia el PM de Program Memory y parecia mas en concordancia.

Y por ultimo cambiar el .DW por unos .hword (16 bits)
Título: Re: Bootloader encriptado para Attiny88
Publicado por: juaperser1 en 23 de Septiembre de 2015, 05:55:13
Perdón por la intromisión, pero me gustaría preguntar algo:

Citar
Creo que está escrito para el compilador de Atmel. Me gustaría utilizar el ensamblador GNU, pero no hay apenas documentación

Por que no quieres usar el de atmel? Es por algo en especial, algún problema que tenga o no te guste, o simplemente es porque quieres trabajar con el de GNU. O es que estas trabajando en linux y no hay IDE de atmel para sistemas linux?

Perdón por el offtopic
Título: Re: Bootloader encriptado para Attiny88
Publicado por: stk500 en 23 de Septiembre de 2015, 06:59:49
Yo de verdad que de Assemble se muy poco, pero en visto en pagina de Alemanas muchos Bootloader por ejemplo el famoso programador Peter Dannegger,
Aqui http://www.mikrocontroller.net/articles/AVR_Bootloader_FastBoot_von_Peter_Dannegger
espero que esto te ayude
Saludos
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 23 de Septiembre de 2015, 07:55:44
Gracias stk500, le estoy echando un vistazo (a lo que consigo entender).

Me gusta el compilador de GNU porque es más genérico. Sirve para muchos micros.

Además, cuando compilas C y miras el listado producido en assembler, utiliza el mismo estilo que el ensamblador.

También puedes utilizar el compilador c avr-gcc para procesar ensamblador.
Si alguna vez combino ensamblador y c, prefiero no mezclar herramientas.

Por último, es una cuestión de apoyo a las herramientas open-source.


Killer: voy a mirar lo de la delta.
Yo estoy estudiando todavía las directivas de ensamblador.
He conseguido que ensamble sin problemas, pero como lo estoy haciendo con el avr-gcc me pide una rutina main que tengo que añadir.
Voy a intentar hacer un programa que desencripte una palabra conocida y que la envíe por la UART todo el tiempo para probar juntas todas las funciones.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 23 de Septiembre de 2015, 08:10:31
Varias implementaciones de XTEA:
   http://wiki.secondlife.com/wiki/XTEA_Strong_Encryption_Implementation

Design of Efficient XTEA Using Verilog:
   http://www.ijsrp.org/research_paper_jun2012/ijsrp-June-2012-18.pdf

Hardware Implementation of XTEA:
   http://teal.gmu.edu/courses/ECE646/project/reports_2006/HI-1-report.pdf

XTEA Block cypher:
   http://people.rit.edu/rab3106/CryptoReport.pdf

JavaScript XTEA:
   http://www.movable-type.co.uk/scripts/tea.html


Test Vectors for TEA and XTEA:
   http://www.cix.co.uk/~klockstone/teavect.htm

Saludos.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: juaperser1 en 23 de Septiembre de 2015, 10:01:39
Citar
Por último, es una cuestión de apoyo a las herramientas open-source.   

Pues para mi es un punto a tu favor, yo también apoyo las herramientas open-source.

Un saludo
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 23 de Septiembre de 2015, 10:13:28
Citar
Me gusta el compilador de GNU porque es más genérico. Sirve para muchos micros.

Eso y que sigue el "standart" de las secciones .text /.data / .bss , etc. Lo cual hace que si te moves a un dsPIC/MIPS/ARM vas a seguir con el mismo manejo..
Y uno de los dolores de cabeza que tuve fue el de aprender eso a la fuerza cuando pase de mis PIC12/16/18 a un dsPIC o demas...
Título: Re: Bootloader encriptado para Attiny88
Publicado por: juaperser1 en 23 de Septiembre de 2015, 11:13:30
Lo mejor, es que algunas empresas, como microchip, cogen el gcc, y te lo venden, poniendo alguna excusa, como la de la optimización.

Umm...no me gusta, es una de las cosas por las que voy a cambiar de marca.

Un saludo
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 23 de Septiembre de 2015, 11:46:43
Estoy parado en un detalle tonto y no consigo seguir.

Programa en asm para hacer un blink (tomado del listado de un programa c que funciona):

Código: [Seleccionar]
.text

.global  delay
delay:
      sbiw r24,1
      brcs .L1
.L2:
      ldi r18,lo8(-30)
      ldi r19,lo8(3)
.L5:
      nop
      subi r18,1
      sbc r19,r0
      cp r18,r0
      cpc r19,r0
      brne .L5
      rjmp .L2
.L1:
      ret



.global  main
main:
      sbi 0xe,3
      sbi 0xd,3
.L8:
      sbi 0xd,0
      ldi r24,lo8(-24)
      ldi r25,lo8(3)
      rcall delay
      cbi 0xd,0
      ldi r24,lo8(-24)
      ldi r25,lo8(3)
      rcall delay
      rjmp .L8

Lo intento compilar así:

Código: [Seleccionar]
d:/Bin/avr8-gnu/bin/avr-gcc.exe -g -mmcu=attiny88 -x assembler-with-cpp boot.asm -o boot.o
d:/Bin/avr8-gnu/bin/avr-gcc.exe -g -mmcu=attiny88 boot.o -o boot.elf

y me aparece error en el segundo comando:

Código: [Seleccionar]
boot.o: In function `__vector_1':
(.text+0x38): multiple definition of `__bad_interrupt'
d:/bin/avr8-gnu/bin/../lib/gcc/avr/4.8.1/../../../../avr/lib/avr25/crttn88.o:(.text+0x0): first defined here
boot.o: In function `__vectors':
(.text+0x0): multiple definition of `__vectors'
d:/bin/avr8-gnu/bin/../lib/gcc/avr/4.8.1/../../../../avr/lib/avr25/crttn88.o:(.vectors+0x0): first defined here
collect2.exe: error: ld returned 1 exit status

¿Alguien sabe cómo compilar esto?
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 23 de Septiembre de 2015, 12:08:52
No entendi bien...

Estas tratando de compilar el ASM ese con gcc
O eso lo llamas de un .c ?

http://stackoverflow.com/questions/21218690/gcrt1-s195-multiple-definition-of-bad-interrupt

Eso tiene el mismo problema.

--------------------------------------------------------------

Ademas no estarias compilandolo 2 veces ?

AVR-GCC es el compilador. Una ves que tenes el codigo objeto ( .o ) o la coleccion de las mismas deberias pasarlo por el linker.
Pero AVR-GCC no es el linker. lo cual estas compilando nuevamente el .o

Creo que avr-gcc ya hace todo.. compila y linkea con una sola pasada.

Sino:
Cualquier cosa busca en el .c que tenes que linker esta usando, seguro que en las propiedades del proyecto ademas trae las opciones que se le agregan a la linea de comando.

(http://microchip.wdfiles.com/local--files/mplabx:libraries/LibraryUse.png)

-------------------------------------------------------------

Proba poniendo el -v o -### asi activa el verbose mode y se puede ver cual es el error

Vi que usa -c para compilar y no linkear

Estas usando assembler-with-cpp cuando tenes solo un archivo solo con ASM ?
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 23 de Septiembre de 2015, 13:25:45
Es que normalmente yo llamo al linker a través del compilador:

Programa: blink.c
Código: [Seleccionar]
/*
  Blink led every second
*/
#include <avr/io.h>

#define BIT_CLEAR(byte, bit)  byte &= (~(1<<(bit)))
#define BIT_SET(byte, bit)    byte |= (1<<(bit))

void delay_ms(unsigned int c) {
   unsigned int i;
   while(c--) {
      for(i=994; i--;) asm("nop");
   }
}


void main(void) {
   BIT_SET(DDRA, 3);  // Port output (transistor)
   BIT_SET(PORTA, 3); // Port high (LEDS ON)

   BIT_SET(DDRA, 0);  // Port output (Cathode)
    
   while(1) {
      BIT_CLEAR(PORTA, 0); // LED ON
      delay_ms(500);
      BIT_SET(PORTA, 0);   // LED OFF
      delay_ms(500);
   }
}


Compilador y linker en windows: _compile.bat

Código: [Seleccionar]
@echo off
SET file=blink
D:/Bin/avr8-gnu/bin/avr-gcc.exe -Os -mmcu=attiny88 -c %file%.c
D:/Bin/avr8-gnu/bin/avr-gcc.exe -Os -mmcu=attiny88 -o %file%.elf %file%.o
D:/Bin/avr8-gnu/bin/avr-objcopy.exe -O ihex %file%.elf %file%.hex
del *.elf
pause

1º Compilador: obtiene el fichero   blink.o
2º Linker : obtiene el fichero *.elf
3º Convierte el fichero *.elf en un fichero *.hex

Y al final obtengo el fichero blink.hex  listo para cargar en el microcontrolador.

Lo que no se es cómo hacerlo sólo para assembler. Imagino que hay que llamar directamente al linker.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 23 de Septiembre de 2015, 13:34:46
Probaria asi:


Código: [Seleccionar]
D:/Bin/avr8-gnu/bin/avr-gcc.exe -Os -mmcu=attiny88 -c -x assembler boot.S
D:/Bin/avr8-gnu/bin/avr-gcc.exe -Os -mmcu=attiny88 -o boot.elf boot.o
D:/Bin/avr8-gnu/bin/avr-objcopy.exe -O ihex boot.elf boot.hex

El -c le dice que lo compile y no lo linkee. Me aseguro con x de que sepa que es un archivo asm.

Sino probaria darle directamente con

Código: [Seleccionar]
D:/Bin/avr8-gnu/bin/avr-gcc.exe -Os -mmcu=attiny88 -x assembler boot.S -o boot.elf
D:/Bin/avr8-gnu/bin/avr-objcopy.exe -O ihex boot.elf boot.hex
Para ver que sale
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 23 de Septiembre de 2015, 13:43:58
Ya lo conseguí.
Cuando los fuentes están sólo en ensamblador, se puede omitir el linker:

Programa en ensamblador: blink2.asm
Código: [Seleccionar]
.text

.global  delay
delay:
.L2:
      ldi r18,lo8(995)
      ldi r19,hi8(995)
.L5:
      nop
      nop
      subi r18,1
      sbc r19,r0
      cp r18,r0
      cpc r19,r0
      brne .L5
      subi r24,1
      sbc r25,r0
      cp r24,r0
      cpc r25,r0
      brne .L2
      ret


.global  main
main:
      cli
      sbi 0xe,3
      sbi 0xd,3
.L8:
      sbi 0xd,0
      ldi r24,lo8(500)
      ldi r25,hi8(500)
      rcall delay
      cbi 0xd,0
      ldi r24,lo8(500)
      ldi r25,hi8(500)
      rcall delay
      rjmp .L8
El programa no está optimizado.


Programa para ensamblar en Windows con avr-gnu: _assembly.bat
Código: [Seleccionar]
@echo off
SET file=blink2
d:/Bin/avr8-gnu/bin/avr-gcc.exe -mmcu=attiny88 -x assembler-with-cpp %file%.asm -o %file%.o
d:/Bin/avr8-gnu/bin/avr-objcopy.exe -O ihex %file%.o %file%.hex
pause

1º Ensamblador  para conseguir fichero objeto blink2.o
2º Convierte fichero objeto en hex: blink2.hex

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 23 de Septiembre de 2015, 13:46:11
Veo que has posteado lo mismo un poco antes, Killer.

Ese segundo método funciona Ok.

Ahora a probar el algoritmo XTEA. Tengo una versión mía que he ido programando en paralelo.
Voy a comparar los dos archivos (el tuyo y el mío) y posteo el resultado.

Pero antes, quiero desensamblar el fichero anterior para ver cómo coloca el vector de reset.
Yo no lo he programado, de forma que imagino que lo hará automáticamente el ensamblador.
Eso no me convence del todo, porque tengo que manejar las posiciones y los vectores a mano.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 23 de Septiembre de 2015, 13:47:46
Suerte Picuino, yo estoy tan interesado que funione como si fuera un proyecto mio  :-/


Y una cosa:

Citar
1º Ensamblador  para conseguir fichero objeto blink2.o
2º Convierte fichero objeto en hex: blink2.hex

Creo que no vendria a ser el .o , sino el .elf directo. recorda que el .o deberia pasar por el linker, y esto ya paso por eso. O me estoy equivocando?


Citar
Eso no me convence del todo, porque tengo que manejar las posiciones y los vectores a mano.

No entiendo lo de ponerlos a mano, lo unico que se es que si pones el programa al final, lo mas seguro es que pierdas los vectores de reset.
Creo que va a depender del linker, el archivo linker que vi tienen ya una seccion destinada a los vectores de interupcion, el que vi se llamaba .intvec.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 23 de Septiembre de 2015, 15:09:51
Bueno, por ahora publico mi rutina de XTEA en asm.
Sólo está comprobado que se ensambla sin problemas. Nada más.

Código: ASM
  1. ;
  2. ;  XTEA decipher routine
  3. ;
  4. #include <avr/io.h>
  5.  
  6. #define  data0       r2
  7. #define  data1       r3
  8. #define  data2       r4
  9. #define  data3       r5
  10. #define  data4       r6
  11. #define  data5       r7
  12. #define  data6       r8
  13. #define  data7       r9
  14. #define  temp0       r10
  15. #define  temp1       r11
  16. #define  temp2       r12
  17. #define  temp3       r13
  18. #define  temp4       r14
  19. #define  temp5       r15
  20. #define  temp6       r16
  21. #define  temp7       r17
  22. #define  suma0       r18
  23. #define  suma1       r19
  24. #define  suma2       r20
  25. #define  suma3       r21
  26. #define  r_index     r22
  27. #define  rounds      r23
  28.  
  29. #define  YL          r28
  30. #define  YH          r29
  31. #define  ZL          r30
  32. #define  ZH          r31
  33.  
  34. #define  XTEA_ROUNDS  64
  35.  
  36. ;
  37. ; Inputs:
  38. ;   data0 ... data7 = 8 bytes of coded data
  39. ;
  40. ; Outputs:
  41. ;   data0 ... data7 = 8 bytes of decoded data
  42. ;
  43.  
  44. xtea_decode:
  45.  
  46.    ; suma = 0xC6EF3720
  47.    ldi    suma0, 0x20
  48.    ldi    suma1, 0x37
  49.    ldi    suma2, 0xEF
  50.    ldi    suma3, 0xC6
  51.  
  52.    ; rounds = 64
  53.    ldi   rounds, XTEA_ROUNDS
  54.  
  55.    ; do {
  56. xtea_decode_loop:
  57.  
  58.    ; temp_a = data0
  59.    movw  temp0, data0
  60.    movw  temp2, data2
  61.  
  62.    ; temp_b = data1
  63.    movw  temp4, data4
  64.    movw  temp6, data6
  65.  
  66.    ; data1 = temp
  67.    movw  data4, temp0
  68.    movw  data6, temp2
  69.  
  70.    ; data0 = temp_b
  71.    movw  data0, temp4
  72.    movw  data2, temp6
  73.  
  74.    ; temp_b = temp
  75.    movw  temp4, temp0
  76.    movw  temp6, temp2
  77.  
  78.  
  79.    ; temp_a <<= 4
  80.    ldi   r_index, 4
  81. xtea_shift_left:
  82.    lsl   temp0
  83.    rol   temp1
  84.    rol   temp2
  85.    rol   temp3
  86.    dec   r_index
  87.    brne  xtea_shift_left
  88.  
  89.  
  90.    ; temp_b >>= 5
  91.    ldi   r_index, 5
  92. xtea_shift_right:
  93.    lsr   temp0
  94.    ror   temp1
  95.    ror   temp2
  96.    ror   temp3
  97.    dec   r_index
  98.    brne  xtea_shift_right
  99.  
  100.  
  101.    ; temp_a ^= temp_b
  102.    eor   temp0, temp4
  103.    eor   temp1, temp5
  104.    eor   temp2, temp6
  105.    eor   temp3, temp7
  106.  
  107.  
  108.    ; temp_a += data1
  109.    add   temp0, data4
  110.    adc   temp1, data5
  111.    adc   temp2, data6
  112.    adc   temp3, data7
  113.  
  114.  
  115.    ; if ((rounds & 1) == 0):
  116.    ;    r1 = (suma>>11) & 3
  117.    sbrc  rounds, 0
  118.    rjmp  xtea_label_1
  119.    mov   r_index, suma1
  120.    lsr   r_index
  121.    rjmp  xtea_label_2
  122.    ; else:
  123.    ;    r1 = suma & 3
  124. xtea_label_1:
  125.    mov   r_index, suma0
  126.    lsl   r_index
  127.    lsl   r_index
  128. xtea_label_2:
  129.    andi  r_index, 0b00001100
  130.  
  131.  
  132.    ; temp_b = xtea_key[r1*4]
  133.    ldi   ZL, lo8(xtea_key_table)
  134.    ldi   ZH, hi8(xtea_key_table)
  135.    add   ZL, r_index
  136.    lds   r_index, SREG
  137.    sbrc  r_index, 0
  138.    inc   ZH
  139.    lpm   temp4, Z+
  140.    lpm   temp5, Z+
  141.    lpm   temp6, Z+
  142.    lpm   temp7, Z+
  143.  
  144.  
  145.    ; temp_b += suma
  146.    add   temp4, suma0
  147.    adc   temp5, suma1
  148.    adc   temp6, suma2
  149.    adc   temp7, suma3
  150.  
  151.  
  152.    ; temp_a ^= temp_b
  153.    eor   temp0, temp4
  154.    eor   temp1, temp5
  155.    eor   temp2, temp6
  156.    eor   temp3, temp7
  157.  
  158.  
  159.    ; data0 -= temp
  160.    sub   data0, temp0
  161.    sbc   data1, temp1
  162.    sbc   data2, temp2
  163.    sbc   data3, temp3
  164.  
  165.  
  166.    ; if ((rounds & 1) == 0):
  167.    ;    suma -= 0x9E3779B9
  168.    sbrc  rounds, 0
  169.    rjmp  xtea_label_3
  170.    subi  suma0, 0xB9
  171.    sbci  suma1, 0x79
  172.    sbci  suma2, 0x37
  173.    sbci  suma3, 0x9E
  174. xtea_label_3:
  175.  
  176.    ;    rounds -= 1
  177.    ; } while(rounds);
  178.    dec   rounds
  179.    breq  xtea_end  
  180.    rjmp  xtea_decode_loop
  181.  
  182. xtea_end:
  183.  
  184. xtea_key_table:
  185.    .byte   0x12, 0x34, 0x56, 0x78
  186.    .byte   0x12, 0x34, 0x56, 0x78
  187.    .byte   0x12, 0x34, 0x56, 0x78
  188.    .byte   0x12, 0x34, 0x56, 0x78


Ahora voy a comprobar si funciona correctamente.

Una vez que funcione voy a intentar optimizarla un poco más. Ahora ocupa 172 bytes.
Para eso me voy a fijar en la rutina de Killer, a ver si entre los 2 podemos reducirla.

Saludos.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 23 de Septiembre de 2015, 15:30:18
Las rutinas son casi iguales.
Yo he unido los dos pasos en uno sólo (con el programa en python) para reducir algunas instrucciones, pero no sé si al pasarlo a asm ha mejorado.

Voy a comprobar si funciona y luego continúo intentando reducir tamaño.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 23 de Septiembre de 2015, 15:42:28
Yo al mio veo como mejorarlo un poco haciendo unas cosas que hiciste vos, que es lo de pasar los terminos de esa forma e incorporar la resta a el loop. lo cual me puede ahorrar unas cuantas lineas creo. tal ves unas 10 creo.

El tuyo lo vi y no hay mucho para mejorar, ejemplo vos haces:

Código: [Seleccionar]
  add   ZL, r_index
   lds   r_index, SREG
   sbrc  r_index, 0
   inc   ZH

yo hago:

Código: [Seleccionar]
    ADD ZL,R0 ; Le sumo el valor de R0 o lo que es igual a 4 * index
     CLR        R0 ; Me aseguro que por mas que caiga donde sea la llave en el programa no se produzca algun error
     ADC ZH,R0 ; Sumandole el carry

Tengo 1 instruccion menos, uso el CLR que no afecta a la bandera C, y luego sumo ZH + R0 + C, como R0 es 0, ZH + C , no se si es lo toma como correcto y no modifica el bit de Carry esto
Una cosa a mejorar en lo tuyo

Código: [Seleccionar]
  dec   rounds
   breq  xtea_end  
   rjmp  xtea_decode_loop
xtea_end:
por

Código: [Seleccionar]
  dec   rounds
   brneq  xtea_decode_loop
xtea_end:



PD: Si queres un highlight de AVR-ASM para el gedit
https://launchpad.net/avrasm-gtk-highlight
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 23 de Septiembre de 2015, 17:08:00
La primera modificación está bien, no me había dado cuenta en la primera pasada. La copio.

La segunda la tenía como tú dices, pero el loop es demasiado largo y la instrucción brne no llega a poder saltar. Quizás si acorto un poco la rutina se pueda.

Al comienzo se intercambian los datos y se copia el primero en los registros temporales. Creo que eso lo puedo acortar un poco y dejarlo más claro:

Código: [Seleccionar]
   ; temp_a = data0
   movw  temp0, data0
   movw  temp2, data2

   ; temp_b = data0
   movw  temp4, data0
   movw  temp6, data2

   ; data0 = data1
   movw  data0, data4
   movw  data2, data6

   ; data1 = temp_a
   movw  data4, temp0
   movw  data6, temp2
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 23 de Septiembre de 2015, 17:20:58
No me habia dado cuenta de la limitacion, pense que no iba a ser tan largo el loop, al menos en el mio como para que eso sucediera.

La forma de acortarlo me parece bien.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 24 de Septiembre de 2015, 15:51:27
No encuentro la forma de reservar SRAM con el ensamblador GNU.
El problema de este programa es que no encuentro un manual.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: stk500 en 24 de Septiembre de 2015, 16:47:46
a ver si esto te sirve
http://www.groupes.polymtl.ca/inf1995/logiciel/progAvr/avr-libc-user-manual-1.8.0.pdf
https://ez.analog.com/thread/10607
http://www.nongnu.org/avr-libc/user-manual/mem_sections.html
aunque yo buscaria mejor por WinAVR , GNU son muchos Gurus  :D
Saludo
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 24 de Septiembre de 2015, 17:00:51
No encuentro la forma de reservar SRAM con el ensamblador GNU.
El problema de este programa es que no encuentro un manual.

No entiendo por que estas reservando RAM? Y ahora que lo pienso tampoco se por que estas programandolo con gcc xD, Cuando es ASM nomas.

O decis que reservar ram el linker para no utilizar direcciones absolutas?
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 24 de Septiembre de 2015, 18:13:07
Cuento los avances:

He conseguido enlazar un programa en c para bootloader con las rutinas en ensamblador para decodificar XTEA y para comunicar con UART.
El programa recibe 8 bytes por UART, los guarda en un buffer SRAM, los decodifica y los vuelve a transmitir por UART.

Me interesaba saber cómo sincronizar la memoria entre el C y el ensamblador. Por ahora, para sincronizar los programas he utilizado  direcciones absolutas a partir de la 0x100 en ensamblador para salvar el valor de los registros. Supongo que el linker utilizará las primeras posiciones de memoria SRAM y no se solaparán
También utilizo un puntero para acceder a los datos del buffer.

Más adelante programaré todo en ensamblador y no tendré el problema de salvar registros ni el de sincronizar RAM.

Por último he utilizado el programa en Python para codificar un texto y enviarlo por la UART. A continuación recibe el mensaje de vuelta del microcontrolador y lo imprime.


El primer programa ha funcionado, pero el mensaje decodificado no se entiende.
Creo que puede ser un problema de el endianess entre Python y el microcontrolador. Voy a seguir depurando hasta que funcione.

Un saludo.

Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 24 de Septiembre de 2015, 18:17:58
a ver si esto te sirve
http://www.groupes.polymtl.ca/inf1995/logiciel/progAvr/avr-libc-user-manual-1.8.0.pdf
https://ez.analog.com/thread/10607
http://www.nongnu.org/avr-libc/user-manual/mem_sections.html

El primero lo conozco. Solo habla de ensamblador metido dentro de código c, no en archivos separados.
El segundo creo que es para micros más avanzados.
El tercero también lo conocía. Habla de secciones de memoria, pero no dice cómo reservar.

Yo lo que quiero es muy simple.
Es que el linker se encargue de situar las variables en SRAM para que se sincronicen los códigos C y ensamblador.
Es equivalente a esto del ensamblador de Atmel:

Código: [Seleccionar]
.DSEG
var1:  .BYTE 1      ; reserve 1 byte to var1

Pero que sirva para el ensamblador de GNU:

Código: [Seleccionar]
.data
?????

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 24 de Septiembre de 2015, 18:35:52
Citar
.comm

Syntax: .comm symbol, length

.comm declares a common symbol named symbol. When linking, a common symbol in one object file may be merged with a defined or common symbol of the same name in another object file. If ld does not see a definition for the symbol - just one or more common symbols - then it will allocate length bytes of uninitialized memory. length must be an absolute expression. If ld sees multiple common symbols with the same name, and they do not all have the same size, it will allocate space using the largest size.

y

Citar
.lcomm

Syntax: .lcomm symbol, length

Reserve length (an absolute expression) bytes for a local common denoted by symbol. The section and value of symbol are those of the new local common. The addresses are allocated in the bss section, so that at run-time the bytes start off zeroed. Symbol is not declared global (see .global), so is normally not visible to ld.

Normalmente uno lo que haria es:

Código: [Seleccionar]
.global Variable
.bss
Variable: .byte 64

Tambien otra que vi es la de definir el lugar

Código: [Seleccionar]
.global Variable
.bss
Variable:  .space 64

Pero parece que se debe usar .comm el cual permite el paso a C de los datos y lo pone en bss.  Lo que no se es si es necesario poner el .bss antes, y el .comm ya lo declara global para que lo use el linker.

Código: [Seleccionar]
.comm Variable,64(Aunque vi que hablan sobre que esto lo crea en una seccion "common" en algunos otros casos, todo depende del OS que se trate)

o

Código: [Seleccionar]
.global Variable
.lcomm Variable,64
(El cual crea la variable en bss, pero por no lo hace global.)


Espero que alguna de estas te de una idea o te sirva. Y ojo que .data es para los datos inicializados, .bss es para datos NO inicializados.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 24 de Septiembre de 2015, 18:48:18
He probado con:

Código: [Seleccionar]
.data
save_reg:  .byte  20

Y no funciona. Cuando salvo los registros en la zona de memoria 'save_reg' se borra el buffer de datos definido en c.
Se solapan los dos.

Voy a declararlo global a ver si el linker se da por enterado.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 24 de Septiembre de 2015, 18:53:26
Falta el icono de "pegarse un tiro"
Llevo horas con esta tontería.
Al final parece que ha funcionado uno de los ejemplos de Killer, añadiendo la sección .data en vez de .bss:

Código: [Seleccionar]
.data
.comm save_reg, 20

Ha pasado la primera prueba y no borra el buffer del c
A ver si sigue funcionando.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 24 de Septiembre de 2015, 18:58:25
Pero lo feo es que data es inicializado :/... Y no era mi objetivo  :mrgreen:. yo quiero no inicializado ! pero si funciona   :roll:


No probaste el de .bss y .lcomm ? O directamente .lcomm solo sin invocar .data o .bss ? Creo que es el mas seguro..
Yo por que si no el compilador trataria de inicializarlo a esa variable. Con lo que llevaria mas espacio ocupado para alojar el valor de la variable a inicializar.

Una cosa mas que me causa duda. Como estas probando todo esto ? (si se puede saber obvio)

EDIT:

Aca encontre un ejemplo, no de Attiny pero si de un MSP430 de TI que usa gcc. y usa el .lcomm directamente.
https://gist.github.com/RickKimball/1303030
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 24 de Septiembre de 2015, 19:41:12
He probado con .bss y me daba error.
Con .lcomm no he probado aún.

Estoy probando desde el pc con un programa Python que codifica con XTEA una cadena de texto y la envía al micro por UART.

El micro recibe la cadena, la decodifica con XTEA y la vuelve a enviar. Por último el programa Python recibe la cadena y la muestra.

Todo funciona OK si quito la codificación. Lo que no funciona por ahora es la rutina de decodificación XTEA del microcontrolador.

Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 24 de Septiembre de 2015, 19:56:01
Puede que sea que la rutina sea distinta en ambos ?

Podrias hacer que te envie los valores intermedios para ver que esta ocurriendo.
Especialmente el de la suma.


Que te envie esos 32 valores para ver si son correctos. o hicimos mal la resta. y luego comprobarlo con el de python.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 24 de Septiembre de 2015, 19:58:30
Sospecho de la key almacenada en flash. Voy a probarla primero.

El programa en asm es este:


Código: ASM
  1. ;
  2. ;  XTEA decipher routine
  3. ;
  4.  
  5. ; *******************************************************************
  6. ;   DECLARACIONES
  7. ; *******************************************************************
  8. #include <avr/io.h>
  9.  
  10. #define  XTEA_ROUNDS  1   // 32
  11. #define  DELTA        0x0 // 0x9E3779B9
  12.  
  13. #define  XTEA_KEY1    0x0 // 0x87654321
  14. #define  XTEA_KEY2    0x0 // 0x87654321
  15. #define  XTEA_KEY3    0x0 // 0x87654321
  16. #define  XTEA_KEY4    0x0 // 0x87654321
  17.  
  18. #define  DELTA_SUMA   (DELTA*XTEA_ROUNDS)
  19.  
  20. // Call saved registers
  21. #define  data0       r2
  22. #define  data1       r3
  23. #define  data2       r4
  24. #define  data3       r5
  25. #define  data4       r6
  26. #define  data5       r7
  27. #define  data6       r8
  28. #define  data7       r9
  29. #define  temp0       r10
  30. #define  temp1       r11
  31. #define  temp2       r12
  32. #define  temp3       r13
  33. #define  buff0       r14
  34. #define  buff1       r15
  35.  
  36. #define  ZL          r30
  37.  
  38.  
  39. // Free registers
  40. #define  rounds      r17
  41. #define  suma0       r18
  42. #define  suma1       r19
  43. #define  suma2       r20
  44. #define  suma3       r21
  45. #define  r_index     r22
  46.  
  47. #define  temp4       r24
  48. #define  temp5       r25
  49. #define  temp6       r26
  50. #define  temp7       r27
  51.  
  52. #define  ZH          r31
  53.  
  54.  
  55. ; *******************************************************************
  56. ;   DATOS EN RAM
  57. ; *******************************************************************
  58. .data
  59. .comm save_reg, 20
  60.  
  61.  
  62. ; *******************************************************************
  63. ;   PROGRAMA
  64. ; *******************************************************************
  65. .text
  66.  
  67. ; xtea_decode
  68. ;
  69. ; Inputs:
  70. ;   data0 ... data7 = 8 bytes of coded data
  71. ;
  72. ; Outputs:
  73. ;   data0 ... data7 = 8 bytes of decoded data
  74. ;
  75.  
  76. .global xtea_decode
  77. xtea_decode:
  78.  
  79.    ; Save registers
  80.    rcall  xtea_save_reg
  81.  
  82.  
  83.    ; suma = 0xC6EF3720 = DELTA*32
  84.    ldi    suma0, lo8(DELTA_SUMA)
  85.    ldi    suma1, hi8(DELTA_SUMA)
  86.    ldi    suma2, hlo8(DELTA_SUMA)
  87.    ldi    suma3, hhi8(DELTA_SUMA)
  88.  
  89.  
  90.    ; rounds = 64
  91.    ldi   rounds, XTEA_ROUNDS*2
  92.  
  93.  
  94.    ; do {
  95. xtea_decode_loop:
  96.  
  97.    ; temp_a = data0
  98.    movw  temp0, data0
  99.    movw  temp2, data2
  100.  
  101.    ; temp_b = data0
  102.    movw  temp4, data0
  103.    movw  temp6, data2
  104.  
  105.    ; data0 = data1
  106.    movw  data0, data4
  107.    movw  data2, data6
  108.  
  109.    ; data1 = temp_a
  110.    movw  data4, temp0
  111.    movw  data6, temp2
  112.  
  113.  
  114.    ; temp_a <<= 4
  115.    ldi   r_index, 4
  116. xtea_shift_left:
  117.    lsl   temp0
  118.    rol   temp1
  119.    rol   temp2
  120.    rol   temp3
  121.    dec   r_index
  122.    brne  xtea_shift_left
  123.  
  124.  
  125.    ; temp_b >>= 5
  126.    ldi   r_index, 5
  127. xtea_shift_right:
  128.    lsr   temp0
  129.    ror   temp1
  130.    ror   temp2
  131.    ror   temp3
  132.    dec   r_index
  133.    brne  xtea_shift_right
  134.  
  135.  
  136.    ; temp_a ^= temp_b
  137.    eor   temp0, temp4
  138.    eor   temp1, temp5
  139.    eor   temp2, temp6
  140.    eor   temp3, temp7
  141.  
  142.  
  143.    ; temp_a += data1
  144.    add   temp0, data4
  145.    adc   temp1, data5
  146.    adc   temp2, data6
  147.    adc   temp3, data7
  148.  
  149.  
  150.    ; if ((rounds & 1) == 0):
  151.    ;    r1 = ((suma>>11) & 3)*4
  152.    sbrc  rounds, 0
  153.    rjmp  xtea_label_1
  154.    mov   r_index, suma1
  155.    lsr   r_index
  156.    rjmp  xtea_label_2
  157.  
  158.    ; else:
  159.    ;    r1 = (suma & 3)*4
  160. xtea_label_1:
  161.    mov   r_index, suma0
  162.    lsl   r_index
  163.    lsl   r_index
  164. xtea_label_2:
  165.    andi  r_index, 0b00001100
  166.  
  167.  
  168.    ; temp_b = xtea_key[r1*4]
  169.    ldi   ZL, lo8(xtea_key_table)
  170.    ldi   ZH, hi8(xtea_key_table)
  171.    add   ZL, r_index
  172.    ldi   r_index, 0
  173.    adc   ZH, r_index
  174.    lpm   temp4, Z+
  175.    lpm   temp5, Z+
  176.    lpm   temp6, Z+
  177.    lpm   temp7, Z+
  178.  
  179.  
  180.    ; temp_b += suma
  181.    add   temp4, suma0
  182.    adc   temp5, suma1
  183.    adc   temp6, suma2
  184.    adc   temp7, suma3
  185.  
  186.  
  187.    ; temp_a ^= temp_b
  188.    eor   temp0, temp4
  189.    eor   temp1, temp5
  190.    eor   temp2, temp6
  191.    eor   temp3, temp7
  192.  
  193.  
  194.    ; data0 -= temp_a
  195.    sub   data0, temp0
  196.    sbc   data1, temp1
  197.    sbc   data2, temp2
  198.    sbc   data3, temp3
  199.  
  200.  
  201.    ; if ((rounds & 1) == 0):
  202.    ;    suma -= 0x9E3779B9
  203.    sbrc  rounds, 0
  204.    rjmp  xtea_label_3
  205.    subi  suma0, lo8(DELTA)
  206.    sbci  suma1, hi8(DELTA)
  207.    sbci  suma2, hlo8(DELTA)
  208.    sbci  suma3, hhi8(DELTA)
  209. xtea_label_3:
  210.  
  211.    ;    rounds -= 1
  212.    ; } while(rounds);
  213.    dec   rounds
  214.    breq  xtea_end_loop
  215.    rjmp  xtea_decode_loop
  216.  
  217. xtea_end_loop:
  218.    ; Load registers
  219.    rcall  xtea_load_reg
  220.    ret
  221.  
  222.  
  223. ; *******************************************************************
  224. ;   FUNCIONES DE APOYO
  225. ; *******************************************************************
  226.  
  227.  
  228. xtea_save_reg:
  229.    ; Save registers in sram
  230.    sts    save_reg+1,  data0
  231.    sts    save_reg+1,  data1
  232.    sts    save_reg+2,  data2
  233.    sts    save_reg+3,  data3
  234.    sts    save_reg+4,  data4
  235.    sts    save_reg+5,  data5
  236.    sts    save_reg+6,  data6
  237.    sts    save_reg+7,  data7
  238.    sts    save_reg+8,  temp0
  239.    sts    save_reg+9,  temp1
  240.    sts    save_reg+10, temp2
  241.    sts    save_reg+11, temp3
  242.    sts    save_reg+12, buff0
  243.    sts    save_reg+13, buff1
  244.    sts    save_reg+14, ZL
  245.    sts    save_reg+15, ZH
  246.  
  247.    movw   buff0, r24
  248.    movw   ZL, buff0
  249.    ld     data0, Z+
  250.    ld     data1, Z+
  251.    ld     data2, Z+
  252.    ld     data3, Z+
  253.    ld     data4, Z+
  254.    ld     data5, Z+
  255.    ld     data6, Z+
  256.    ld     data7, Z+
  257.    ret
  258.    
  259.  
  260. xtea_load_reg:
  261.  
  262.    ; Load registers from sram  
  263.    movw   ZL, buff0
  264.    st     Z+, data0
  265.    st     Z+, data1
  266.    st     Z+, data2
  267.    st     Z+, data3
  268.    st     Z+, data4
  269.    st     Z+, data5
  270.    st     Z+, data6
  271.    st     Z+, data7
  272.  
  273.    lds    data0, save_reg+1  
  274.    lds    data1, save_reg+1  
  275.    lds    data2, save_reg+2  
  276.    lds    data3, save_reg+3  
  277.    lds    data4, save_reg+4  
  278.    lds    data5, save_reg+5  
  279.    lds    data6, save_reg+6  
  280.    lds    data7, save_reg+7
  281.    lds    temp0, save_reg+8  
  282.    lds    temp1, save_reg+9  
  283.    lds    temp2, save_reg+10
  284.    lds    temp3, save_reg+11
  285.    lds    buff0, save_reg+12
  286.    lds    buff1, save_reg+13
  287.    lds    ZL,    save_reg+14
  288.    lds    ZH,    save_reg+15
  289.  
  290.    ret
  291.  
  292.  
  293. ; *******************************************************************
  294. ;   DATOS EN FLASH
  295. ; *******************************************************************
  296. xtea_key_table:
  297.    .long  XTEA_KEY1
  298.    .long  XTEA_KEY2
  299.    .long  XTEA_KEY3
  300.    .long  XTEA_KEY4

Las rutinas para salvar y restaurar registros son temporales. En la versión final las quitaré
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 24 de Septiembre de 2015, 20:03:22
Una pregunta.....

La llave en python lo estas haciendo

0x12345678
0x12345678
0x12345678
0x12345678

De esa forma ?

Si lo guardas en little endian es

0x78563412
y no
0x87654321

Espero que no sea eso xD

Sino en python deberias probar con
0x21436587
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 25 de Septiembre de 2015, 09:22:12
Para evitar problemas de ese tipo he comenzado con una llave = 0 y un delta = 0

La rutina sigue dando errores.

Voy a enviar un dato = 0 y si sigue dando errores, le pongo un ramo a la Virgen de la Candelaria, una vela a San José y me tomo un descanso, porque no sé qué más hacer.

Título: Re: Bootloader encriptado para Attiny88
Publicado por: juaperser1 en 25 de Septiembre de 2015, 09:46:16
Citar
Voy a enviar un dato = 0 y si sigue dando errores, le pongo un ramo a la Virgen de la Candelaria, una vela a San José y me tomo un descanso, porque no sé qué más hacer.

te propongo ir a ver al señor roca, y ademas de que te olvides del problema haciendo otras cosas que no ocupen tu cerebro, en cuanto te des cuenta te llegará la inspiración.

a mi me funciona :D :D
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 25 de Septiembre de 2015, 11:12:21
Bueno, no ha hecho falta echar mano del santo patrón.
He simplificado al máximo haciendo sólo una ronda con shift y nada más.
Como eso también funcionaba mal, me he dado cuenta de que el shift era lo que fallaba.

Corregido. Ahora mismo envío 8 bytes cifrados al microcontrolador y los recibo descifrados. La rutina XTEA funciona.  ((:-))

Lo siguiente es implementar un protococo que reciba datos de 8 en 8, los agrupe y los grabe en flash

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 25 de Septiembre de 2015, 11:13:52
Código: [Seleccionar]
;
;  XTEA decipher routine
;

; *******************************************************************
;   DECLARACIONES
; *******************************************************************
#include <avr/io.h>

#define  XTEA_ROUNDS  32
#define  DELTA        0x9E3779B9

#define  XTEA_KEY1    0x87654321
#define  XTEA_KEY2    0x87654321
#define  XTEA_KEY3    0x87654321
#define  XTEA_KEY4    0x87654321

#define  DELTA_SUMA   (DELTA*XTEA_ROUNDS)

// Call saved registers
#define  data0       r2
#define  data1       r3
#define  data2       r4
#define  data3       r5
#define  data4       r6
#define  data5       r7
#define  data6       r8
#define  data7       r9
#define  temp0       r10
#define  temp1       r11
#define  temp2       r12
#define  temp3       r13
#define  buff0       r14
#define  buff1       r15

#define  ZL          r30


// Free registers
#define  rounds      r17
#define  suma0       r18
#define  suma1       r19
#define  suma2       r20
#define  suma3       r21
#define  r_index     r22

#define  temp4       r24
#define  temp5       r25
#define  temp6       r26
#define  temp7       r27

#define  ZH          r31


; *******************************************************************
;   DATOS EN RAM
; *******************************************************************
.data
.comm save_reg, 20


; *******************************************************************
;   PROGRAMA
; *******************************************************************
.text

; xtea_decode
;
; Inputs:
;   data0 ... data7 = 8 bytes of coded data
;
; Outputs:
;   data0 ... data7 = 8 bytes of decoded data
;

.global xtea_decode
xtea_decode:

   ; Save registers
   rcall  xtea_save_reg


   ; suma = 0xC6EF3720 = DELTA*32
   ldi    suma0, lo8(DELTA_SUMA)
   ldi    suma1, hi8(DELTA_SUMA)
   ldi    suma2, hlo8(DELTA_SUMA)
   ldi    suma3, hhi8(DELTA_SUMA)


   ; rounds = 64
   ldi   rounds, XTEA_ROUNDS*2


   ; do {
xtea_decode_loop:

   ; temp_a = data0
   movw  temp0, data0
   movw  temp2, data2

   ; temp_b = data0
   movw  temp4, data0
   movw  temp6, data2

   ; data0 = data1
   movw  data0, data4
   movw  data2, data6

   ; data1 = temp_a
   movw  data4, temp0
   movw  data6, temp2


   ; temp_a <<= 4
   ldi   r_index, 4
xtea_shift_left:
   lsl   temp0
   rol   temp1
   rol   temp2
   rol   temp3
   dec   r_index
   brne  xtea_shift_left


   ; temp_b >>= 5
   ldi   r_index, 5
xtea_shift_right:
   lsr   temp7
   ror   temp6
   ror   temp5
   ror   temp4
   dec   r_index
   brne  xtea_shift_right


   ; temp_a ^= temp_b
   eor   temp0, temp4
   eor   temp1, temp5
   eor   temp2, temp6
   eor   temp3, temp7


   ; temp_a += data1
   add   temp0, data4
   adc   temp1, data5
   adc   temp2, data6
   adc   temp3, data7


   ; if ((rounds & 1) == 0):
   ;    r1 = ((suma>>11) & 3)*4
   sbrc  rounds, 0
   rjmp  xtea_label_1
   mov   r_index, suma1
   lsr   r_index
   rjmp  xtea_label_2

   ; else:
   ;    r1 = (suma & 3)*4
xtea_label_1:
   mov   r_index, suma0
   lsl   r_index
   lsl   r_index
xtea_label_2:
   andi  r_index, 0x0C


   ; temp_b = xtea_key[r1*4]
   ldi   ZL, lo8(xtea_key_table)
   ldi   ZH, hi8(xtea_key_table)
   add   ZL, r_index
   ldi   r_index, 0
   adc   ZH, r_index
   lpm   temp4, Z+
   lpm   temp5, Z+
   lpm   temp6, Z+
   lpm   temp7, Z+


   ; temp_b += suma
   add   temp4, suma0
   adc   temp5, suma1
   adc   temp6, suma2
   adc   temp7, suma3


   ; temp_a ^= temp_b
   eor   temp0, temp4
   eor   temp1, temp5
   eor   temp2, temp6
   eor   temp3, temp7


   ; data0 -= temp_a
   sub   data0, temp0
   sbc   data1, temp1
   sbc   data2, temp2
   sbc   data3, temp3


   ; if ((rounds & 1) == 0):
   ;    suma -= 0x9E3779B9
   sbrc  rounds, 0
   rjmp  xtea_label_3
   subi  suma0, lo8(DELTA)
   sbci  suma1, hi8(DELTA)
   sbci  suma2, hlo8(DELTA)
   sbci  suma3, hhi8(DELTA)
xtea_label_3:


   ;    rounds -= 1
   ; } while(rounds);
   dec   rounds
   breq  xtea_end_loop
   rjmp  xtea_decode_loop

xtea_end_loop:
   ; Load registers
   rcall  xtea_load_reg
   ret


; *******************************************************************
;   FUNCIONES DE APOYO
; *******************************************************************


xtea_save_reg:
   ; Save registers in sram
   sts    save_reg+1,  data0
   sts    save_reg+1,  data1
   sts    save_reg+2,  data2
   sts    save_reg+3,  data3
   sts    save_reg+4,  data4
   sts    save_reg+5,  data5
   sts    save_reg+6,  data6
   sts    save_reg+7,  data7
   sts    save_reg+8,  temp0
   sts    save_reg+9,  temp1
   sts    save_reg+10, temp2
   sts    save_reg+11, temp3
   sts    save_reg+12, buff0
   sts    save_reg+13, buff1
   sts    save_reg+14, ZL
   sts    save_reg+15, ZH

   movw   buff0, r24
   movw   ZL, buff0
   ld     data0, Z+
   ld     data1, Z+
   ld     data2, Z+
   ld     data3, Z+
   ld     data4, Z+
   ld     data5, Z+
   ld     data6, Z+
   ld     data7, Z+
   ret
   

xtea_load_reg:

   ; Load registers from sram 
   movw   ZL, buff0
   st     Z+, data0
   st     Z+, data1
   st     Z+, data2
   st     Z+, data3
   st     Z+, data4
   st     Z+, data5
   st     Z+, data6
   st     Z+, data7

   lds    data0, save_reg+1 
   lds    data1, save_reg+1 
   lds    data2, save_reg+2 
   lds    data3, save_reg+3 
   lds    data4, save_reg+4 
   lds    data5, save_reg+5 
   lds    data6, save_reg+6 
   lds    data7, save_reg+7
   lds    temp0, save_reg+8 
   lds    temp1, save_reg+9 
   lds    temp2, save_reg+10
   lds    temp3, save_reg+11
   lds    buff0, save_reg+12
   lds    buff1, save_reg+13
   lds    ZL,    save_reg+14
   lds    ZH,    save_reg+15

   ret


; *******************************************************************
;   DATOS EN FLASH
; *******************************************************************
xtea_key_table:
   .long  XTEA_KEY1
   .long  XTEA_KEY2
   .long  XTEA_KEY3
   .long  XTEA_KEY4
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 25 de Septiembre de 2015, 12:18:01
No me quedo claro, tenias un problema en el shift de ASM o en el shift de python?

Bueno de todas formas como que ya casi lo tenes terminado. no le falta mucho, hacer que espere por 8 es lo de menos
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 25 de Septiembre de 2015, 13:25:47
El problema era el shift a derechas del asm.

No creas, todavía tengo para rato.

Tengo que implementar el protocolo. Acabo de ponerle un checksum fletcher para comprobar que los datos cifrados se han recibido ok.
Si todo está bien, a continuación se desencripta y graba los datos en flash.
Por último, todos los datos de la flash menos el bootloader deben tener un checksum determinado antes de saltar a la dirección de inicio.

Además el bootloader tiene que esperar un tiempo en el inicio, para recibir datos. Si no recibe datos, salta a la aplicación.

El vector de reset está siempre fijo apuntando al bootloader, de manera que el vector de reset recibido hay que desplazarle (otro problema más)

Todas las pruebas las hago en c que es más flexible y rápido. Por último tengo que pasar todo a ensamblador y minimizar el tamaño.


Saludos.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 25 de Septiembre de 2015, 13:39:03
El vector de reset está siempre fijo apuntando al bootloader, de manera que el vector de reset recibido hay que desplazarle (otro problema más)

Eso estaba pensando, si lo pones al final al codigo para que te permita cambiar los vectores, te vas a tener que asegurar que el vector de reset no lo cambie nunca :P.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 25 de Septiembre de 2015, 14:13:58
Si. Es una medida de seguridad. Igual que comprobar que el bootloader no se sobreescribe.

He hecho medidas de tiempo y tarda unos 7700 ciclos en desencriptar 8 bytes (0.96 ms)
En total cada página de memoria de 64 bytes tardará:

   6.1ms  recepción por UART de 70bytes (datos + checksum + dirección) a 115200 baud
   7.7ms desencriptado
   4ms en borrar memoria (cpu halted)
   4ms en escribir memoria (cpu halted)
   0.01 ms enviar acknowledge
   0.01 ms otras rutinas (checksum, ...)

Total = 22 ms para grabar una página de 64 bytes.

Unos 2.7 segundos para grabar toda la flash de 8kbytes.

Es suficiente.

Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 26 de Septiembre de 2015, 07:21:04
He tenido algún problema de corrupción de datos trabajando a la vez con c y con assembler.

Atmel recomienda que las variables se declaren en C y que se enlacen en assembler.

Ejemplo C:
Código: C
  1. char buff_reg[32];
  2.  
  3. int main(void) {
  4. ...


Ejemplo ASM:
Código: C
  1. .data
  2. .extern    buff_reg
  3.  
  4. .text
  5. ; inicio de las rutinas


Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 30 de Septiembre de 2015, 18:48:17
Cuento los avances.

Estos días he estado pensando en una rutina para entrar en el bootloader.
Tenía que cumplir muchas condiciones y no era sencillo:

1. Las líneas de comunicación del bootloader son serie (UART) y comparten pines con el interface I2C.
2. Durante el reset, puede que el maestro I2C esté enviando datos a 100kbaud y hay que evitar que eso haga entrar al bootloader.
3. El bootloader quiero que funcione desde un conversor USB-RS232 o desde un Arduino. Esto significa que todas las señales que le llegan al bootloader tienen que mantener un estandar de tiempos RS232
4. La codición de entrada al bootloader tiene que ser robusta, pero al mismo tiempo que no se pueda entrar en modo bootloader de forma accidental.
5. La rutina que detecte la condición de entrada al bootloader debe ser sencilla de implementar, que ocupe poco código.

Después de darle muchas vueltas llegué a la conclusión de que lo mejor era entrar en el bootloader si se daba la condición de un pulso de nivel bajo de un tiempo determinado durante los dos primeros segundos después del reset:

  --------|             |-------
          |-------------|


Pensé que el pulso podía ser de 15 milisegundos a nivel bajo.
De esta forma se puede crear con un conversor USB-UART simplemente enviando un cero a 600 baudios.
Este tiempo es relativamente grande y no se va a confundir con un pulso de I2C.
Por otro lado, suponiendo que haya ruido en la patilla de entrada, es difícil que aparezca un pulso negativo de exactamente 15ms.
Es un tiempo demasiado alto para un espúreo y lejos de los 10ms de la frecuencia de red.

He programado ya una rutina y ensambla sin errores:

Código: [Seleccionar]
;
; Comprueba durante 2 segundos si hay un pulso bajo de 15 milisegundos.
; Si se cumple la condición, entrar en el bootloader
;
#define counter        r24
#define counter_hi     r25
#define cycles         r26
#define pulse_time     r27

#define BOOT_PULSE_WAIT_MS    2000
#define BOOT_PULSE_MS           15
#define BOOT_PULSE_COUNTER    ((BOOT_PULSE_WAIT_MS * 250) / BOOT_PULSE_MS)
#define DELAY_3CY_COUNTER     (((BOOT_PULSE_MS*8000/250)-15)/3)

boot_pulse:
   ldi   counter, lo8(BOOT_PULSE_COUNTER)
   ldi   counter_hi, hi8(BOOT_PULSE_COUNTER)
   clr   pulse_time                ; uint8_t pulse_time = 0

boot_pulse_loop:                   ; DO {
   ldi   cycles, DELAY_3CY_COUNTER ;    delay_us(60)  (480-15 cycles)
   rcall Delay3Cycle               ;

   sbic  UART_PIN, UART_RX         ;    IF (RX == LOW):  (5cy)
   rjmp  boot_pulse_high           ;
   inc   pulse_time                ;       pulse_time++
   rjmp  boot_pulse_2              ;
boot_pulse_high:                   ;    ELSE:  (6cy)
   cpi   pulse_time, 245           ;       IF (pulse_time > 245*delay_us && pulse_time < 256*delay_us):
   brsh  bootloader                ;          GOTO bootloader
   clr   pulse_time                ;       pulse_time = 0;

boot_pulse_2:
   sbiw   counter, 1               ;    counter--;  (4cy)
   brne   boot_pulse_loop          ; } WHILE(counter)

   rjmp   run_user_program         ; GOTO run_user_program

Esta rutina mejora mucho en tamaño a que hice ayer. Ocupa 30bytes (15 instrucciones)

Ahora sólo falta hacer pruebas.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 30 de Septiembre de 2015, 19:46:49
Tengo mis ciertas dudas del programa....

Como que ocurra el envio en un punto en que el contador ya esta terminandose, supongamos que en esos 2 segundos  se envie a los 1.99s  dejandote 10ms. Es lo unico que veo que puede fallar.

Por que me preocupa esto? Por que es una comunicacion RS232 y no sabes cuando se reseteo el micro, prefiero mil veces un boton el cual tenes un "control" de cuando vas a entrar al modo bootloader.
Tampoco podes enviar nada indicando del reset por que sos un esclavo para el I2C. Y tenes que asegurarte de que no va a ocurrir con el I2C eso de mantenerlo por 15ms. Como por ejemplo que las resistencias de pull.up lo tenga la otra placa, y al alimentar la placa con el micro y el bootloader no tenga nada que lo este pulleando a VCC.

Creo que podrias achicar un poco mas el programa con un cambio, no es mucho creo que son 2 instrucciones., pero nuevamente hay que ver los ciclos de las intrucciones.


Código: ASM
  1. boot_pulse:
  2.    ldi   counter, lo8(BOOT_PULSE_COUNTER)
  3.    ldi   counter_hi, hi8(BOOT_PULSE_COUNTER)
  4.    clr   pulse_time                ;
  5.  
  6. boot_pulse_loop:                   ;
  7.    ldi   cycles, DELAY_3CY_COUNTER ;
  8.    rcall Delay3Cycle               ; ???? Donde esta esa funcion ? ademas rcall lleva 3 ciclos tinyAVR + 4 del return y te llenaria el STACK si no usas un return.
  9.  
  10.    sbis  UART_PIN, UART_RX         ;
  11.    rjmp  boot_pulse_2              ;
  12. boot_pulse_high:                   ;
  13.    cpi   pulse_time, 246           ; Incremento en 1 por el efecto del inc pulse_time de abajo
  14.    brsh  bootloader                ;
  15.    clr   pulse_time                ;
  16.  
  17. boot_pulse_2:
  18.    inc   pulse_time                ;
  19.    sbiw   counter, 1               ;
  20.    brne   boot_pulse_loop          ;
  21.  
  22.    rjmp   run_user_program         ; GOTO run_user_program
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 01 de Octubre de 2015, 10:17:13
Gracias por el código, Killer.

Tengo mis ciertas dudas del programa....

Como que ocurra el envio en un punto en que el contador ya esta terminandose, supongamos que en esos 2 segundos  se envie a los 1.99s  dejandote 10ms. Es lo unico que veo que puede fallar.

No es un problema, sólo un límite de tiempo. Eso se puede cambiar en el programa para ampliarlo hasta 4 segundos.


Por que me preocupa esto? Por que es una comunicacion RS232 y no sabes cuando se reseteo el micro, prefiero mil veces un boton el cual tenes un "control" de cuando vas a entrar al modo bootloader.

Tengo botones, pero no quiero utilizarlos. La placa está destinada a usuarios sin conocimientos. Si aprietan el botón por error, va a entrar el bootloader y pensarán que la placa no funciona. No quiero que dé esa impresión.

El pulso debe tener exactamente 15 milisegundos. No funciona con 14ms y tampoco con 16ms.
Si se lleva a Vcc no hay problema (no hay pulso). Si se lleva a GND no hay problema (el pulso es mayor de 15ms).
Es una condición muy difícil de cumplir por error.

Por otro lado es una condición muy sencilla de cumplir para el programa que carga el bootloader desde el PC.

Tampoco podes enviar nada indicando del reset por que sos un esclavo para el I2C. Y tenes que asegurarte de que no va a ocurrir con el I2C eso de mantenerlo por 15ms. Como por ejemplo que las resistencias de pull.up lo tenga la otra placa, y al alimentar la placa con el micro y el bootloader no tenga nada que lo este pulleando a VCC.

Sí que puedo enviar datos de vuelta. De hecho las líneas funcionan como RS232 en modo bootloader (con TX y RX) y funcionan en modo I2C el resto del tiempo.
Esa es otra razón por la que quiero evitar que la placa entre en modo bootloader así como así. Sólo debe hacerlo cuando realmente sea necesario.

En cuanto al I2C, es muy difícil que a 100kbaud vaya a generar un pulso bajo de exactamente 15ms, ni más ni menos.


Creo que podrias achicar un poco mas el programa con un cambio, no es mucho creo que son 2 instrucciones., pero nuevamente hay que ver los ciclos de las intrucciones.


Código: ASM
  1. boot_pulse:
  2.    ldi   counter, lo8(BOOT_PULSE_COUNTER)
  3.    ldi   counter_hi, hi8(BOOT_PULSE_COUNTER)
  4.    clr   pulse_time                ;
  5.  
  6. boot_pulse_loop:                   ;
  7.    ldi   cycles, DELAY_3CY_COUNTER ;
  8.    rcall Delay3Cycle               ; ???? Donde esta esa funcion ? ademas rcall lleva 3 ciclos tinyAVR + 4 del return y te llenaria el STACK si no usas un return.
  9.  
  10.    sbis  UART_PIN, UART_RX         ;
  11.    rjmp  boot_pulse_2              ;
  12. boot_pulse_high:                   ;
  13.    cpi   pulse_time, 246           ; Incremento en 1 por el efecto del inc pulse_time de abajo
  14.    brsh  bootloader                ;
  15.    clr   pulse_time                ;
  16.  
  17. boot_pulse_2:
  18.    inc   pulse_time                ;
  19.    sbiw   counter, 1               ;
  20.    brne   boot_pulse_loop          ;
  21.  
  22.    rjmp   run_user_program         ; GOTO run_user_program

Ese programa salta al bootloader si el pulso es mayor de 15ms (esto quiero evitarlo, como he comentado antes)

El código que falta es sencillo:

Código: [Seleccionar]
Delay3Cycle:
   subi  cycles, 1
   brne  Delay3Cycle
   ret
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 01 de Octubre de 2015, 10:30:40
Uno de los problemas que tengo consiste en que el oscilador interno debe estar muy bien calibrado para que todo funcione.
El programa tiene una tolerancia desde 14.7ms hasta 15.3ms (+-2%)

Esto es aceptable cuando se trabaja con osciladores a cristal, pero el oscilador interno del Attiny tiene una tolerancia inicial del 10%.
Sólo si se calibra, se consigue una tolerancia del 1% en frecuencia.

Hay dos soluciones:
1. Calibrar el oscilador en el bootloader: Es complejo y engorroso. Se puede hacer por medio de la EEPROM, pero alarga el programa y no es muy seguro.

2. Enviar pulsos de diferentes tiempos, 13.5ms, 14ms, 14.5ms,, 15ms, 15.5ms, 16ms, 16.5ms
    Esto se puede hacer sin problema con el Arduino, pero no sé si se puede calibrar con tanta exactitud un USB-UART
    Otro problema es que algunos de estos pulsos se van a interpretar como si fuesen datos por parte del Bootloader Attiny y pueden desincronizar la transmisión de datos UART.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 01 de Octubre de 2015, 14:19:32
Citar
Ese programa salta al bootloader si el pulso es mayor de 15ms (esto quiero evitarlo, como he comentado antes)

Tu programa estaba igual comparaba de 245-255, en mi caso era igual. Y para arreglarlo dejarlo como queres, podes comparar cuando se terminan los 2 segundos. si esta dentro de un rango (que es lo que deberias hacer) entonces  continuas con el bootloader.
El mayor problema que encuentro es que trabajamos en 8 bits, y un overflow de por asi decirlo 510 ( 256 -250 ) seria valido.

Codigo (no lo expuesto antes):
Código: ASM
  1. ; Caso que solo se admita un solo pulso en esos 2 segundos, solo se tomara en cuenta el ultimo, espera todos lso 2 segundos para saber si entro o no al bootloader
  2.  
  3.  
  4. #define         PULSE_MIN       245
  5. #define         PULSE_MAX       250
  6.  
  7. boot_pulse:
  8.         ldi   counter, lo8(BOOT_PULSE_COUNTER)
  9.         ldi   counter_hi, hi8(BOOT_PULSE_COUNTER)
  10.         clr   pulse_time                ;
  11.      
  12. boot_pulse_loop:                        ;
  13.         ld      cycles, DELAY_3CY_COUNTER ;
  14.         rcall   Delay3Cycle               ;
  15.      
  16.         sbis    UART_PIN, UART_RX       ;
  17.         rjmp    boot_pulse_low          ;
  18.         set                             ; T indica que la señal subio, si llega a bajar y esta seteado entonces procedo a borrarlo
  19.         rjmp    boot_loop_end           ; Subio asi que voy a preguntar de nuevo por la entrada
  20. boot_pulse_low:                         ; Caso que estuviera bajo
  21.         brtc    boot_pulse_low2         ; Esta seteado T? subio y bajo ? Aca me quedan 2 opciones mantener el mayor ocupo 2 registros o borro todo
  22.         clr     pulse_time              ; Borro en este caso
  23. boot_pulse_low2:
  24.         inc     pulse_time              ; Incremento debido a que paso 1, a pesar de que subio y bajo.
  25. boot_loop_end:
  26.         sbiw    counter, 1              ;
  27.         brne    boot_pulse_loop         ;
  28.  
  29.         cpi     pulse_time, PULSE_MIN   ;
  30.         brlo    run_user_program        ;
  31.         cpi     pulse_time, PULSE_MAX   ;
  32.         brsh    run_user_program
  33.         rjmp    bootloader              ; GOTO bootloader
  34.  
  35.  
  36.  
  37. ; Caso que solo el primer pulso entre y cumpla las condiciones entre a modo bootloader sin tener que esperar los 2 segundos
  38.  
  39.  
  40. #define         PULSE_MIN       245
  41. #define         PULSE_MAX       250
  42.  
  43. boot_pulse:
  44.         ldi   counter, lo8(BOOT_PULSE_COUNTER)
  45.         ldi   counter_hi, hi8(BOOT_PULSE_COUNTER)
  46.         clr   pulse_time                ;
  47.      
  48. boot_pulse_loop:                        ;
  49.         ld      cycles, DELAY_3CY_COUNTER ;
  50.         rcall   Delay3Cycle               ;
  51.      
  52.         sbis    UART_PIN, UART_RX       ;
  53.         rjmp    boot_pulse_low          ;
  54.         set                             ; T indica que la señal subio, si llega a bajar y esta seteado entonces procedo a borrarlo
  55.         cpi     pulse_time, PULSE_MIN   ; Si subio puede indicar 2 casos, 1ero que estaba arriba, lo cual no va a incrementar en nada pulse_time
  56.         brlo    boot_loop_end           ; 2do, que estaba en 0 y paso a 1, en ese caso va a tener un valor pulse_time y se va a comparar
  57.         cpi     pulse_time, PULSE_MAX   ; si estaba fuera de rango, entonces va a continuar. Si llega un 0 se resetea pulse_time,
  58.         brsh    boot_loop_end          
  59.         rjmp    bootloader              ; Caso que estuviera dentro de los valores
  60. boot_pulse_low:                         ; Caso que estuviera bajo
  61.         brtc    boot_pulse_low2         ; Esta seteado T? subio y bajo ? Aca me quedan 2 opciones mantener el mayor ocupo 2 registros o borro todo
  62.         clr     pulse_time              ; Borro en este caso
  63. boot_pulse_low2:
  64.         inc     pulse_time              ; Incremento debido a que paso 1, a pesar de que subio y bajo.
  65. boot_loop_end:
  66.         sbiw    counter, 1              ;
  67.         brne    boot_pulse_loop         ;
  68.  
  69.         rjmp    run_user_program        ; GOTO programa de usuario

Deje 2 codigos, hay un comentario arriba de cada codigo, utilize bastantes banderas por que no se si hay un equivalente a la direccion actual del PC en ese momento tal como hay en MPASM del PIC ( $ ).
Y tambien me excedi en el programa. todo depende exactamente como es que queres que funcione. Podria haber comparado nomas con 1 valor y luego usart T en caso de un overflow.

Mi otra pregunta, no posee un cristal tu placa? Uno de 32k ? como para un reloj ?
Citar
2. Enviar pulsos de diferentes tiempos, 13.5ms, 14ms, 14.5ms,, 15ms, 15.5ms, 16ms, 16.5ms
    Esto se puede hacer sin problema con el Arduino, pero no sé si se puede calibrar con tanta exactitud un USB-UART
    Otro problema es que algunos de estos pulsos se van a interpretar como si fuesen datos por parte del Bootloader Attiny y pueden desincronizar la transmisión de datos UART.

Pero cuando cambien las condiciones de temperatura se perdio todo lo bueno de eso. Ademas seria un valor inicial y nunca mas tocarlo. es decir una calibracion en la "fabrica". Sino implementarlo en el micro si va a ser un dolor de cabeza. Como discriminas que esos pulsos no sean de otra cosa ?

Citar
Tengo botones, pero no quiero utilizarlos. La placa está destinada a usuarios sin conocimientos. Si aprietan el botón por error, va a entrar el bootloader y pensarán que la placa no funciona. No quiero que dé esa impresión.

Si tiene 3/4 botones, tenerlos presionados a todos por 2/4 segundos en el reset no es ningun error. O peor aun si pensas que sea 2 botones por mas tiempo.
Lo bueno de esto es que si se suelta ya no entra mas a modo bootloader.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 01 de Octubre de 2015, 17:36:18
Si, en mi programa puede haber desbordamiento del contador.

En ese caso sólo se salta al bootloader si el contador está entre 245 y 255 (10 valores de 255)
Esto se cumplirá en 15ms +- 0.3ms y en 30.3ms +-3ms y en 45.6ms +-3ms  etc, etc.

En cualquier caso un pulso aleatorio sólo tendrá una probabilidad del 4% de colarse como bootloader.


La placa no posee cristal. Como dices, una calibración "de fábrica" tiene muchos problemas. Por eso pensaba en enviar un tren de pulsos de diferentes tamaños. Así alguno conseguirá iniciar el bootloader.

Lo de los botones también lo había pensado. En la placa hay 6. En este caso me parece un poco engorroso andar apretando un monton de pulsadores con una mano mientras con la otra se resetea (o se conecta Vcc). Lo veo engorroso para el usuario. Nunca me gustó lo del Ctrl+Alt+Supr. El que no lea el manual (más de la mitad del mundo) no conseguirá actualizar el firmware.
Un usuario inexperto es algo de otro mundo. Cualquiera que haya estado en un servicio de atención al cliente lo ha vivido de cerca.

(http://changlonet.com/blog/wp-content/uploads/2007/dilbert_skects.png)

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 01 de Octubre de 2015, 17:37:12
Voy a leer el nuevo código más despacio.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 01 de Octubre de 2015, 17:44:34
Hay otra posibilidad que no me terminaba de gustar:

Que la aplicación de usuario entre en el bootloader. No me parece elegante. Esto implica que debe haber una aplicación de usuario desde el comienzo.

Como la aplicación de usuario es siempre mía, yo puedo controlarla. Pero no me gusta depender de ella. Si en algún momento se corrompe, adiós bootloader también.

Sí que se podría utilizar como una opción más  (no la única).

De esta forma, puedo enviar una orden I2C para que la placa entre en modo bootloader. Se elimina la necesidad de quitar corriente o de resetear la placa. Es todavía más elegante.

El problema es que no puedo depender siempre de este método, pero es un buen complemento al otro.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 02 de Octubre de 2015, 11:26:29
Hay una cosa que no entiendo del linker.

He hecho este programa:
Código: [Seleccionar]
.text
.global main
main:
   rjmp  main

Sólo tiene una instrucción y compilado ocupa 64 bytes ????

Los 40 bytes iniciales son los vectores de interrupción, pero ¿que pasa con los otros 24?
Aquí no hay que inicializar variables ni nada.

¿Cómo puedo quitar el enlace al CRT0 y dejar el código sin más?

Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 02 de Octubre de 2015, 12:20:02
No hay que inicializar variables con lo que las variables no ocupan espacio, pero el CRTO0/1 si lo hace, y lo tenes siempre.


Citar
¿Cómo puedo quitar el enlace al CRT0 y dejar el código sin más?

Deja de compilarlo con el de C y hace un ASM solo. Haces todo el bootloader en ASM, y luego cuando terminas si llamas al crt0 de tu programa.
O fijate si encontras una opcion para el gcc para indicarle que no lo agregue a ese startup.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 02 de Octubre de 2015, 13:20:08
Ya tengo todo en asm. Pero sigue linkando el crt0.
No encuentro la opción para eliminarlo. Utilizo las mismas opciones del picoboot (que no tiene crt0) pero a mí sí me lo añade.
No consigo eliminarlo.

Voy a leer esto que promete:
Compiling assembler files with avr-gcc without C runtime
http://quanttype.net/posts/2014-01-27-avr-gcc-assembler.html
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 02 de Octubre de 2015, 13:25:53
Citar
avr-ld -e init -o foo.elf foo.o

Código: [Seleccionar]
    .global init
init:
    rjmp main

Citar
-e entry
--entry=entry
    Use entry as the explicit symbol for beginning execution of your program, rather than the default entry point. If there is no symbol named entry, the linker will try to parse entry as a number, and use that as the entry address (the number will be interpreted in base 10; you may use a leading 0x for base 16, or a leading 0 for base 8).

Ahi esta la opcion xD
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 03 de Octubre de 2015, 05:12:07
Con esa opción por fín lo conseguí.  :-/
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 03 de Octubre de 2015, 05:14:06
Código: [Seleccionar]
avr-ld.exe  -section-start=.bootloader=8000  --entry=main -o prog.elf   prog1.o  prog2.o  prog3.o
Enlaza con main, pero directamente, sin incluir las rutinas de inicialización.

Ahora me toca inicializar a mí a mano. Creo que inicializando el puntero de stack y algún puerto será suficiente.
Sobre todo tengo que pensar en los agujeros de seguridad.


Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 03 de Octubre de 2015, 16:51:59
Última versión del algoritmo XTEA:

Código: [Seleccionar]
;
;  XTEA DECIPHER ROUTINE
;

; *******************************************************************
;   DECLARATIONS
; *******************************************************************
#define DATA_REGISTER_INIT_ADDRESS   0x02
#define  data0       r2
#define  data1       r3
#define  data2       r4
#define  data3       r5
#define  data4       r6
#define  data5       r7
#define  data6       r8
#define  data7       r9
#define  temp0       r10
#define  temp1       r11
#define  temp2       r12
#define  temp3       r13
#define  buff0       r14
#define  buff1       r15

#define  rounds      r17
#define  sum0        r18
#define  sum1        r19
#define  sum2        r20
#define  sum3        r21
#define  r_index     r22
#define  r_loop      r23
#define  temp4       r24
#define  temp5       r25
#define  temp6       r26
#define  temp7       r27

#define  YL          r28
#define  YH          r29
#define  ZL          r30
#define  ZH          r31


#define  XTEA_ROUNDS  32
#define  DELTA        0x9E3779B9

#define  XTEA_KEY1    0x87654321
#define  XTEA_KEY2    0x87654321
#define  XTEA_KEY3    0x87654321
#define  XTEA_KEY4    0x87654321

#define  DELTA_SUM   (DELTA*XTEA_ROUNDS)
#define  CARRY        0


; *******************************************************************
;   SRAM DATA
; *******************************************************************
.data
.extern data_buff

; *******************************************************************
;   PROGRAM
; *******************************************************************
.text


; *******************************************************************
;   MODULE: XTEA_DECODE                          144 bytes
; *******************************************************************
;
; xtea_decode_block
;
; Inputs:
;   data0 ... data7 = 8 bytes of coded data
;
; Outputs:
;   data0 ... data7 = 8 bytes of decoded data
;

xtea_decode:

   ; sum = 0xC6EF3720 = DELTA*32
   ldi    sum0, lo8(DELTA_SUM)
   ldi    sum1, hi8(DELTA_SUM)
   ldi    sum2, hlo8(DELTA_SUM)
   ldi    sum3, hhi8(DELTA_SUM)


   ; rounds = XTEA_ROUNDS * 2
   ldi   rounds, XTEA_ROUNDS*2

   ; do {
xtea_decode_loop:

   ; temp_a = data0
   movw  temp0, data0
   movw  temp2, data2

   ; temp_b = data0
   movw  temp4, data0
   movw  temp6, data2

   ; data0 = data1
   movw  data0, data4
   movw  data2, data6

   ; data1 = temp_a
   movw  data4, temp0
   movw  data6, temp2


   ; temp_a <<= 4
   ldi   r_index, 4
xtea_shift_left:
   lsl   temp0
   rol   temp1
   rol   temp2
   rol   temp3
   dec   r_index
   brne  xtea_shift_left


   ; temp_b >>= 5
   ldi   r_index, 5
xtea_shift_right:
   lsr   temp7
   ror   temp6
   ror   temp5
   ror   temp4
   dec   r_index
   brne  xtea_shift_right


   ; temp_a ^= temp_b
   eor   temp0, temp4
   eor   temp1, temp5
   eor   temp2, temp6
   eor   temp3, temp7


   ; temp_a += data1
   add   temp0, data4
   adc   temp1, data5
   adc   temp2, data6
   adc   temp3, data7


   ; r1 = ((sum>>11) & 3)*4
   mov   r_index, sum1
   lsr   r_index
   ; if ((rounds & 1) == 1):
   ;    r1 = (sum & 3)*4
   sbrs  rounds, 0
   rjmp  xtea_label_2
   mov   r_index, sum0
   lsl   r_index
   lsl   r_index
xtea_label_2:
   andi  r_index, 0x0C


   ; temp_b = xtea_key[r1*4]
   ldi   ZH, hi8(xtea_key_table)
   ldi   ZL, lo8(xtea_key_table)
   add   ZL, r_index
#ifndef BOOTLOADER_IN_PAGE
   ldi   r_index, 0
   adc   ZH, r_index
#endif

   lpm   temp4, Z+
   lpm   temp5, Z+
   lpm   temp6, Z+
   lpm   temp7, Z+


   ; temp_b += sum
   add   temp4, sum0
   adc   temp5, sum1
   adc   temp6, sum2
   adc   temp7, sum3


   ; temp_a ^= temp_b
   eor   temp0, temp4
   eor   temp1, temp5
   eor   temp2, temp6
   eor   temp3, temp7


   ; data0 -= temp_a
   sub   data0, temp0
   sbc   data1, temp1
   sbc   data2, temp2
   sbc   data3, temp3


   ; if ((rounds & 1) == 0):
   ;    sum -= 0x9E3779B9
   sbrc  rounds, 0
   rjmp  xtea_label_3
   subi  sum0, lo8(DELTA)
   sbci  sum1, hi8(DELTA)
   sbci  sum2, hlo8(DELTA)
   sbci  sum3, hhi8(DELTA)
xtea_label_3:


   ;    rounds -= 1
   ; } while(rounds);
   dec   rounds
   breq  xtea_end_loop
   rjmp  xtea_decode_loop

xtea_end_loop:
   ret


; *******************************************************************
;   XTEA KEY TABLE                               16 bytes 
; *******************************************************************
xtea_key_table:
   .long  XTEA_KEY1
   .long  XTEA_KEY2
   .long  XTEA_KEY3
   .long  XTEA_KEY4
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 03 de Octubre de 2015, 17:14:42
Ya casi lo tenes. A que te referis con agujeros de seguridad ?
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 04 de Octubre de 2015, 04:23:30
Casi tenía completada una versión, cuando me dí cuenta que reduciéndo el tamaño al máximo ocupaba 420 bytes.
Es demasiado, así que me he planteado quitar todo lo que no sea imprescindible.

He quitado un bucle de la rutina xtea, para que sólo reciba y decodifique 8bytes a la vez. Ahora escribir la página de flash por completo depende del bootloader del PC

Otras cuestiones no puedo delegarlas, porque tengo que imaginar que el bootloader es hostil. Por ejemplo, mantener el vector de reset apuntando al bootloader o impedir la escritura en las páginas donde está alojado el bootloader.

En la rutina de inicialización colocaré lo imprescindible: un cli (no quiero que salte a otro sitio durante la carga), inicialización del stack, puertos y alguna cosa más.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 04 de Octubre de 2015, 04:31:06
La duda que me surge es, ¿dónde recolocar la dirección de inicio de la aplicación de usuario? (el vector de reset de usuario)
Lo más cómodo y rápido sería utilizar otro vector de interrupción dentro de los 4 primeros:
INT0, INT1, PCINT0

A mí me sirve, pero si más adelante quiero utilizar el bootloader para otra aplicación con esas interrupciones utilizadas, tendría que cambiarlo.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 04 de Octubre de 2015, 06:31:41
Yo pensaba en poner el bootloader junto con la tabla de vectores y no al final. De esa forma nunca se puede escribir los mismos.

Luego en tu programa que vas a cargar en el linker definis que la flash no comienza en 0x0000 sino ( supongamos que es la pagina que sigue) en 0x100, Lo que haces vos en tu tabla de vectores es:

- El de reset apuntarlo al bootloader y cuando finaliza el bootloader hacer un salto a 0x100 (que seria el nuevo vector de reset),
- El siguiente vector supongamos que esta en 0x04 , hacer un salto a 0x104. Y asi para todos los vectores que tenga el microcontrolador.  A no ser que quieras usar alguno para el bootloader  El cual seria algo parecido al de reset. ( es decir pasaria por un codigo antes )

Lo que estarias haciendo es crear una tabla alternativa de vectores. Con el correspondiente penalidad que es la de tener ese salto agregado. Pero que seguro no te va a afectar.
Ventajas? Te olvidas de que si hay algun cambio en los vectores de interrupcion, no tengas que obligar al bootloader que el vector de reset sea SI o SI el bootlader, ya que este va a estar fijo, todos los vectores van a estar disponibles, si en algun momento decidis usar otra interrupcion, esta va a estar lista para usarse, sin necesidad de cambiar nada. de tu bootloader y creando la interrupcion en el programa en C como lo haces siempre.

El bootloader solo escribiria apartir de la primer pagina desocupada (en el ejemplo 0x100) y para el programa en C seria como si nada hubiese ocurrido. Ya que va a ocupar desde 0x100 en adelante.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 04 de Octubre de 2015, 07:32:53
El problema que veo es ocupar 40 bytes extra.
Imagino que los vectores del Attiny al estar implementados con saltos relativos, no van a tener problema con el desplazamiento.
Pero eso significa desplazar todo el código. Todo el código debe ser relativo, sin saltos absolutos... (por ejemplo icall Z)

Ahora mismo me estoy peleando con el tamaño. He conseguido ocupar menos de 6 páginas de 64 bytes y no sé si llegaré a las 5 páginas:

  160 bytes   XTEA Decipher
    50 bytes   UART routines
  152 bytes   Bootloader

Bootloader: (152 bytes)
   14 bytes   Init routine
   28 bytes   Rutina de entrada al bootloader (pulso de 15ms)
   18 bytes   Recepción de datos uart y llamada a decodificación xtea
   20 bytes   Comprobar la dirección de escritura en flash (cambio de vector de reset y no escribir páginas de bootloader)
   18 bytes   Mover datos a la memoria temporal de flash
     8 bytes   Si la dirección es el final de una página, grabar datos en flash
   12 bytes   Rutinas de grabación de la flash
   28 bytes   Comprobar el checksum de la Flash. Si es correcto, saltar a la rutina de usuario. (previene errores ante un corte de corriente)
     6 bytes   Saltos varios.

Total = 362 bytes

De las dos primeras hay ya poco donde rascar. El bootloader no veo cómo reducirle en 42 bytes para que ocupe una página menos.
Si no consigo reducirle, todavía tengo 22 bytes (11 instrucciones) para mejorar lo presente.



Me estoy planteando si alguna de esas rutinas las podría pasar al bootloader del PC (o del Arduino) sin peligro de corromper la memoria


Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 04 de Octubre de 2015, 15:06:11
A mi consideracion:

Si, crear una tabla alternativa son 40 bytes extra (20 instrucciones si implementas todos los vectores), lamentablemente no se puede reposicionar. Pero pienso que te solucionaría la vida. Haciendo lo que dije esto no seria necesario:

 - 20 bytes   Comprobar la dirección de escritura en flash (cambio de vector de reset y no escribir páginas de bootloader)

Por que directamente comenzas de cierta pagina. Haciendo que C crea que tiene el mismo integrado pero esta ves con 6 paginas menos de memoria.
Es algo facil de modificar en el archivo de linker. y solo tendrias 20 bytes mas, tal ves gracias a eso tengas otro ahorro. Obviamente tu programa solo requiere una modificacion en el linker que seria la direccion final o el largo de la flash.

Otra ventaja que tendrias es que NUNCA pero NUNCA ante un corte de luz mientras estes programando vas a perder el bootloader, en tu caso aunque sea pequeña la ventana entre borrado de esa pagina de flash + grabacion tenes posiblidades de que ocurra. Si ocurre ¿como pensas "arreglarlo", enviandole el bootloader para que lo grabe la otra persona? ¿un bootloader desencriptado con las llaves a la vista? No serviria de nada tener un bootloader asi a mi parecer, ya que nunca deberia caer en las manos de los demas. Como vos dijiste, creer que te enfrentas al usuario mas bruto posible.

Sino como bien decis tenes que reducir 11 instrucciones. Aunque parezca poco si observas es casi uno de los items mas grandes de tu bootloader y a no ser que saques ( externalizes  o quites) uno de esos items no lo veo factible. Y conviene ocupar toda la pagina, completando las 6.

Un posible ahorro seria. Estas usando CALLs/PUSH/POP ? o simplemente son JMP ? si solo usas JMP y no usas el stack podrias evitar iniciarlo.
O si lo usas crear un stack en un punto que no moleste y sea mas facil de cargar, ejemplo que solo la parte alta del stack se cargue. en el registro del espacio I/O y no ambos, son 2 nstrucciones menos.

No se que mas decirte, imagino que lo tenes bien programado y que reducir esos 22 bytes van a doler y mucho. Asi que queda en vos si ves como achicarlo en 5 paginas si es posible o irte por las 6.

Citar
Imagino que los vectores del Attiny al estar implementados con saltos relativos, no van a tener problema con el desplazamiento.
Pero eso significa desplazar todo el código. Todo el código debe ser relativo, sin saltos absolutos... (por ejemplo icall Z)

Son todos RJMP, que si ocupas 6 paginas , son 384 bytes y la "nueva tabla" ( tabla del verdadero programa ) comenzaria desde 385, los RJMP ( ocupan 1 palabra ) y acepta valores entre -2K y 2k
El programa en C se manejara como quiera, con RJMP k , con RCALL k, ICALL Z, es decir de forma indirecta o relativa, eso por que cambies las dimensiones de las FLASH no vas a tener control o no va a cambiar.
Tu bootloader lo haces todos RJMP y RCALL ( que ocupan menos cantidad de memoria ) ya que estas dentro del posible direccionamiento de los mismos que es 2K. Y como nombre en la primer oracion, tu maximo objetivo es llegar a la pagina 7 y que esta al alcance por demasia.

Una cosa mas que estas mas al tanto vos del Attiny y tal ves estamos divagando demasiado.
La proteccion contra lectura de la FLASH ¿como funciona?,¿es un bit como en el caso de los PIC ?, ¿hay sectores no protegidos?.
Cuando necesitas grabar en la flash, ¿tenes que deshabilitar la proteccion ?

Si la ultima pregunta es correcta entonces estas ante uno de los agujeros de seguridad que buscas, cualquier persona podria darle actualizar  el Attiny y a mitad de programacion desconectarlo, luego leer y con un poco de suerte, si se estaba escribiendo o borrando en ese momento va a tener acceso a toda la FLASH incluido tu bootloader con las Keys. ya que va a estar desprotegido.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 04 de Octubre de 2015, 16:29:17
Con lo que me has comentado, creo que la opción de colocar el bootloader al comienzo es mejor.
Nunca se borrará y eso es importante.

Los 20 bytes sirven para comprobar dos direcciones (la del vector de reset y la del bootloader) Si cambio al comienzo, sólo hay una dirección que comprobar y eso se reduce.

Lo de recolocar el programa con el linker, lo estudiaré. No creo que vaya a ser complicado y el linker se encargará de recolocar todas las direcciones.

He estado revisando todo y ahora el bootloader es un poco más grande . Entre otras cosas, al reducir tamaño borré el envío por UART de una señal ACK para sincronizar las dos partes.


El Attiny tiene muchas opciones de seguridad, creo que más que un PIC.
Antes de grabar el uC hay que borrarle entero (en esto creo que no hay problema)
También se puede impedir el acceso al uC por el interface serie ICSP. Sólo borrando el micro en modo paralelo puedes volver a utilizarle.

Todas estas opciones de los FUSES tengo que estudiarlas mejor para optimizarlas. La idea es que una vez que el bootloader esté instalado, se impida por completo con un fuse la conexión ICSP. Después todos esos pines se pueden utilizar como entradas/salidas.

El init del stack ya está optimizado:
Código: [Seleccionar]
   ; Setup Stack Pointer Address
   ldi    temp4, hi8(RAMEND)
   out    SPH, temp4
Da igual dónde esté SPL, siempre va a funcionar porque habrá como mínimo 256 bytes debajo.
Ahora no utilizo SRAM, así que la pila no me molesta.


Voy a hacer el cambio del bootloader a las direcciones bajas y a ver cómo queda.

Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 04 de Octubre de 2015, 16:46:21
Citar
Los 20 bytes sirven para comprobar dos direcciones (la del vector de reset y la del bootloader) Si cambio al comienzo, sólo hay una dirección que comprobar y eso se reduce.

No vas a tener que comprobar nada. Si lo cambias al comienzo, todo el bootloader no se va a mover. Y los vectores de tu programa en C comenzaran ocupando los 40 bytes de la pagina 7 ( si es que ocupas 6 paginas ) en el orden como si estuvieran desde la posicion 0x00.

Incluso tu bootloader podria ni siquiera necesitar un salto al final. Si no que directamente siga su camino hasta la primer instruccion del programa en C ( que es el vector de reset del mismo )

PD: Espero no estar repitiendo algo que ya lo tenes claro  :mrgreen:

Y cuando puedas fijate sobre eso de la memoria, si podes deshabilitar la lectura de la EEPROM desde el exterior sea por ICSP o como sea es algo muy poderoso, tanto que si te confundiste no podrias grabar mas el micro a traves de un programador externo :).
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 04 de Octubre de 2015, 18:28:43
Tengo que comprobar que la dirección de escritura es mayor que la zona de bootloader (ahora ocupa unos 420 bytes en total) . En realidad son sólo 3 instrucciones que ocupan 6 bytes.
La dirección de escritura a la flash la envía el bootloader del PC después de los datos.

Si, es un modo muy poderoso. Lo descubrí con un uC al que ya no puedo acceder. Se quedó congelado con un programa que enciende y apaga leds.
La solución que me queda es desoldarle y poner otro.

Cuando el bootloader esté suficientemente probado, usaré ese modo. También por eso me interesa que sea tan seguro. Un fallo y no hay vuelta atrás.

Saludos.

Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 04 de Octubre de 2015, 19:01:42
A lo que voy es que no debes comprobar eso. Por que tu bootloader deberia escribir desde donde termina en adelante ( una direccion fija, y hablo de paginas obviamente ).
A no ser que quieras cargar por partes tu programa.. Pero no creo que generes 3 codigos distintos y envies 1 por uno.
Tu bootloader escriibiria desde donde termina ( una direccion fija de memoria, algunos compiladores ofrecen funciones para esto ) hasta el final de la flash ( otra direccion fija, algunos compiladores ofrecen una constante para esto ). Suponiendo que envias los datos en orden para ser escritos asi no necesitas una posicion de memoria.

Lo unico que deberia asegurarse es que el programa en C no supere el tamaño de flash que dispone y esto lo hace el linker.

Si por X causa vos no modificaste el linker y comienza en 0x00 ahi vas a tener problemas sea como sea el bootloader. Saltos realtivos no va a tener problemas pero saltos indirectos si ya que la direccion generada por el linker va a ser otra. ( a nos ser que sean todas relativas y te salves)

Otro problema que puede presentarse y su solucion, es que el bootloader se asegure con un loop infinito en la ultima posicion de memoria + encender una salida para indicar ese fallo ( 2 instrucciones ). En el caso que el programa C tenga un error y no tenga un loop infinito. Asi no entra al bootloader nuevamente, en caso de este error y solo se cumple tu modo de entrada al bootloader. Esto sirve tambien para el primer error en el caso que le erres con el linker.

Cualquier fallo nunca el bootloader se modificaria, ya que no esta dentro del rango de memoria que va a programar el mismo, el unico error que puede existir es de programacion que le erres a esa posicion de memoria inicial y lo termines reescribiendo vos.
Al no modificarse el bootloader es totalmente recuperable.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 05 de Octubre de 2015, 18:11:30
Comento avances.
Ya funciona el bootloader del Attiny88 en ensamblador.
Ahora estoy programando el bootloader del lado PC en Python.
Menuda diferencia. El paso de ensamblador a Python es como haber dado un paseo de varias horas hasta lo alto de una montaña y luego viajar en helicóptero. De repente en Python los avances son rapidísimos, el código sale solo, los errores se corrijen sin dificultad, es como ir volando.
Cada día me gusta más Python.

Bueno, al grano.
Esto de programar en assembler para el Attiny me ha recordado la época en la que programaba en ensamblador para el Z80 del Spectrum o aquel primer microcontrolador 8051 que programé en código máquina con un montón de interruptores para asignar las direcciones y los datos en binario.
Esto no lo vuelvo a repetir ni harto de vino. La próxima vez desarrollo todo en C y me lo pienso dos veces antes de optimizar tamaño o velocidad en ensamblador.

Lo que me queda claro es que la arquitectura AVR es muy distinta a la del PIC. Tiene un montón de registros (32 bytes) con los que operar rapidísimo (1 instrucción por ciclo de reloj) incluso en modo 16 bits (copia de registros, resta, comparación con cero, etc.)
Se pueden hacer virguerías con los registros sin necesidad de memoria SRAM (nada menos que todo un bootloader de 420 bytes con encriptado XTEA)
La pila es estupenda, puede llenar toda la SRAM con llamadas a funciones y con almacenamiento de datos. Eso hace a la arquitectura muy flexible y preparada para compiladores C. Desde luego la arquitectura de máquina me gusta mucho más que la de los PIC.
Por otro lado se echan de menos algunas instrucciones, por ejemplo: "decrementa y salta si no vale zero" que son habituales en otras arquitecturas.

Por el precio que tiene el Attiny88 (0.50€ una unidad (http://es.rs-online.com/web/p/microcontroladores/6963159/)), la potencia de su arquitectura y de sus herramientas de desarrollo, el número de pines (32), el tamaño de memoria (8kbytes flash, 512 bytes ram, 64bytes eeprom), no encuentro un sustituto igual.
La documentación del compilador/ensamblador es escasa y difícil de encontrar, pero al final he conseguido resolver todos los problemas, que no eran pocos.
Hay que tener en cuenta que el tool chain (compilador, ensamblador, linker, etc) es completamente open-source y gratuíto (GNU)

Del PIC sólo echo de menos los estupendos periféricos que tienen algunos de sus micros.
 
Un saludo.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: KILLERJC en 05 de Octubre de 2015, 18:30:50
Si es lo feo que tiene ASM. Yo estoy escribiendo sobre el dsPIC en ASM con el compilador XC16. Hay cosas que si son demasiado engorrosas hacerlas que en C hubiera sido mucho mas facil, aunque todavia lo que no encuentro es como en C crea o usar una instruccion MAC con lo compleja que es, Pero bueno eso esta en ASM, y seguro que hay una funcion que lo hace :P.

En cierto, yo cuando me puse los AVR tambien extrañe algunas cosas que tenia el PIC, no por su corto set de intrucciones, sino por que me parece que habia cosas que faltaban. Los AVR funcionan parecido como los otros nucleos de microcontroladores tales como ARM/PIC24/dsPIC/MIPS. En el que es necesario traer de la memoria a los registros trabajarlos y enviarlos de nuevo. Que a diferencia de los PIC16/18 podes acceder directo. Otra de las buenas es que su memoria no esta dividida en bancos.
Y por ultimo el tema de las instrucciones depende mucho si necesitas tomar datos desde la memoria trabajrlas y guardarlas te lleva varios ciclos mas, pero que por suerte tiene muchos registros los cuales podes llenar con cosas, aunque C por ahi no lo aproveche a full a esto, como uno lo puede hacer en ASM.

En fin toda la pelea Atmel vs PIC se basa en: utilizar 4 ciclos de reloj para 1 instruccion y la memoria separada en bancos. Y como un codigo se ejecuta mas rapido en uno que en otro.

Lo que a mi me extraño tambien como bien decis son los perifericos, para mi el attiny tiene mejores timers que unos PIC, pero solo tener I2C ? una UART no? hasta me parecio raro que tuviera I2C y no UART.
Pero nada compite contra el precio. Lo bueno de ahora Picuino es que con esto Podes usarlo en casi todos los micros de AVR, tal ves lo unico que cambie es la direccion de pagina donde va a estar ubicada, un ifdef solucionaria la vida para hacerlo portable para todos los atmel.
Siempre y cuando mantengan los registros en el mismo lugar :P

En fin, ya que lo terminaste, a mi me parecio un hermoso desafio, y me gusto mientras duro.

Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 05 de Octubre de 2015, 19:08:55
Bueno, el proyecto aún no está terminado.
Funciona el código ASM del lado del Attiny, que no es poco. Pero aún me queda:

1. Programar un encriptador que transforme automáticamente el archivo *.hex en un archivo *.xtea encriptado (casi lo tengo terminado)
2. Programar un bootloader para enviar los datos encriptados desde un PC al Attiny (casi lo tengo terminado)
3. Generar automáticamente un programa para que Arduino envíe los datos encriptados al bootloader
4. Probar los bootloader con diferentes problemas externos (cortes de corriente, ruido, desconexión de cables, etc)
5. Testear que funcionan todos los mecanismos de detección de errores (checksum  de transmisión y checksum de flash)
6. Programar el attiny con los fuses más seguros que se pueda

Y seguro que aparecen algunos puntos más.
Título: Re: Bootloader encriptado para Attiny88
Publicado por: Picuino en 06 de Octubre de 2015, 08:18:39
Primer programa en Python (este lenguaje cada día me gusta más)
Este programa lee y convierte todos los archivos del directorio con formato *.hex de intel, en archivos en formato *.cyp con la información encriptada con el algoritmo XTEA

Primero se parte de una tabla de memoria llena de números aleatorios, que comienza en la dirección después del bootloader
A continuación se colocan en esa tabla los datos del programa, provenientes del archivo *.hex. Todos los datos que no caben en la tabla anterior se desechan.
Después se encripta toda la tabla en grupos de 8 bytes (algoritmo XTEA)
Por último se guarda en el disco toda la tabla en un archivo *.cyp
Este archivo *.cyp se compone de líneas que comienzan con ':', después la dirección de memoria, 8 bytes codificados y al final un checksum de línea.

Programa Python:
Código: Python
  1. import os
  2. import ctypes
  3. import random
  4.  
  5. flash_range = [64*7, 1024*8]
  6.  
  7. xtea_key = [0x00112233, 0x44556677, 0x8899AABB, 0xCCDDEEFF]
  8. xtea_rounds = 32
  9.  
  10.  
  11. def main():
  12.    print 'XTEA Cypher.\nMem range = 0x%04X .. 0x%04X\n' % tuple(flash_range)
  13.    hexfiles = [f for f in os.listdir('.') if f[-4:].lower() == '.hex']
  14.    for hexfile in hexfiles:
  15.       print hexfile
  16.       flash = randflash(flash_range[0], flash_range[1])
  17.       data = read_hexfile(hexfile)
  18.       filldata(flash, data)
  19.       coded = encode(flash)
  20.       dump(coded, hexfile)
  21.  
  22.  
  23. def dump(coded, hexfile):
  24.    xtea_file = hexfile[:-4] + '.cyp'
  25.    data = []
  26.    for line in coded:
  27.       data.append(':%04X %02X%02X%02X%02X%02X%02X%02X%02X %02X\n' % ((line[0],) + tuple(line[1:]) + (256-checksum(line),)))
  28.    fo = open(xtea_file, 'wt')
  29.    fo.write(''.join(data))
  30.    fo.close()
  31.  
  32.  
  33. def filldata(flash, data):
  34.    for line in data:
  35.       addr = line[0]
  36.       for i in range(1, len(line)):
  37.          if addr < flash_range[0] or addr > flash_range[1]:
  38.             continue
  39.          flash[addr - flash_range[0]] = line[i]
  40.          addr += 1
  41.      
  42.  
  43. def encode(flash):
  44.    xtea = []
  45.    addr = flash_range[0]
  46.    for j in range(0, len(flash), 8):
  47.       xtea.append([addr] + xtea_encode(flash[j:j+8]))
  48.       addr += 8
  49.    return xtea
  50.      
  51.  
  52.  
  53. def xtea_encode(data):
  54.    global xtea_key
  55.    XTEA_DELTA = 0x9E3779B9
  56.    data0 = data[0] + (data[1]<<8) + (data[2]<<16) + (data[3]<<24)
  57.    data1 = data[4] + (data[5]<<8) + (data[6]<<16) + (data[7]<<24)
  58.    suma = 0
  59.    rounds = xtea_rounds
  60.    while(rounds):
  61.       data0 += (((data1<<4) ^ (data1>>5)) + data1) ^ (suma + xtea_key[suma & 3])
  62.       data0 = uint32(data0)
  63.       suma = uint32(suma + XTEA_DELTA)
  64.       data1 += (((data0<<4) ^ (data0>>5)) + data0) ^ (suma + xtea_key[(suma>>11) & 3])
  65.       data1 = uint32(data1)
  66.       rounds -= 1
  67.    data[0] = int(data0 & 0xFF)
  68.    data[1] = int((data0>>8) & 0xFF)
  69.    data[2] = int((data0>>16) & 0xFF)
  70.    data[3] = int((data0>>24) & 0xFF)
  71.    data[4] = int(data1 & 0xFF)
  72.    data[5] = int((data1>>8) & 0xFF)
  73.    data[6] = int((data1>>16)& 0xFF)
  74.    data[7] = int((data1>>24)& 0xFF)
  75.    return data  
  76.  
  77.  
  78. def uint32(data):
  79.     return ctypes.c_uint32(data).value
  80.  
  81.  
  82. def randflash(addr_init, addr_end):
  83.    random.seed(1)
  84.    length = int((addr_end - addr_init + 7) / 8) * 8
  85.    return [random.randint(0, 255) for i in range(length)]
  86.  
  87.  
  88. def read_hexfile(filename):
  89.    data = []
  90.    f = open(filename, 'rt')
  91.    for line in f:
  92.       hexdata(data, line)
  93.    f.close()
  94.    return data
  95.  
  96.  
  97. def hexdata(data, line):
  98.    DATA = 0
  99.    if line[0] != ':':
  100.       return
  101.    line = line.strip()
  102.    tam  = int(line[1:1+2], 16)
  103.    addr = int(line[3:3+4], 16)
  104.    typ  = int(line[7:7+2], 16)
  105.    byte = []
  106.    for i in range(tam):
  107.       byte.append(int(line[9+i*2:9+i*2+2], 16))
  108.    if checksum(line) == 0 and typ == DATA:
  109.       data.append([addr] + byte)
  110.  
  111.  
  112. def checksum(line):
  113.    checksum = 0
  114.    if type(line) == type('text'):
  115.       for i in range(1, len(line), 2):
  116.          checksum += int(line[i:i+2], 16)
  117.          checksum = checksum % 256
  118.    if type(line) == type(['list']):
  119.       for i in line:
  120.          checksum += i
  121.          checksum = checksum % 256
  122.    return checksum
  123.    
  124. main()


Ejemplo *.cyp:
Código: [Seleccionar]
:01C0 E391AA3F274F9036 A7
:01C8 9952CA230F0FE373 EC
:01D0 6E00D2742C2B5400 D1
:01D8 982F2B26E0C5FB63 0D
:01E0 750C0B74DFC0B697 34
:01E8 F3292371DBC89993 99
:01F0 504AFC40DC8BB05B C8
:01F8 42BC51B4C58281A4 99
:0200 24B2F6572142D214 94
:0208 06E84E19224A1BF2 2A
:0210 932E9BA3A91A2802 04
:0218 FCA3EDE3E4D65180 EE
:0220 887C7570ABE1E431 56
:0228 A0B75783D7887F67 62
:0230 43D010914743126D 13
:0238 085972BD421545DD BF
:0240 4BF7928A298C2DAD D3
:0248 A2A1901D92ECE85A 08
:0250 935F43C8626895B1 A3
:0258 8B675B29D7B005DA CC
:0260 FE87AD9D378B8B19 6B
:0268 B5764E916825ACDF 76
:0270 174A6F93B4EB6915 10
:0278 83536D8C42311A2E FE
:0280 130FCFB298A026FB 84
:0288 309E881FB9C0D2EC CC
:0290 D9C2080DE1F4FC67 88
:0298 750B6426D50FE80B 87
:02A0 7AE7AACB09E00D7D 17