2010-04-15 17 views
14

Recientemente recogí una copia de Applied Cryptography por Bruce Schneier y ha sido una buena lectura. Ahora entiendo cómo funcionan varios algoritmos delineados en el libro, y me gustaría comenzar a implementar algunos de ellos en C.¿Qué tiene de malo cambiar 32 bits de una variable de 32 bits?

Una cosa que muchos algoritmos tienen en común es dividir una clave de x bits en varias teclas y-bit más pequeñas. Por ejemplo, la clave de Blowfish, X, es de 64 bits, pero debe dividirla en dos mitades de 32 bits; Xl y Xr.

Aquí es donde me estoy atascado. Soy bastante bueno con C, pero no soy el más fuerte cuando se trata de operadores bit a bit y similares.

Después de un poco de ayuda en el IRC, me las arreglé para llegar a estas dos macros:

#define splitup(a, b, c) {b = a >> 32; c = a & 0xffffffff; } 
#define combine(a, b, c) {a = (c << 32) | a;} 

donde A es 64 bits y B y C son de 32 bits. Sin embargo, el compilador me advierte sobre el hecho de que estoy cambiando una variable de 32 bits por 32 bits.

Mis preguntas son las siguientes:

  • lo que es malo trata de cambiar a 32 bits variables de 32 bits? Supongo que no está definido, pero estas macros parecen estar funcionando.
  • Además, ¿sugeriría que lo hiciera de otra manera?

Como ya he dicho, estoy bastante familiarizado con C, pero los operadores bit a bit y similares todavía me dan dolor de cabeza.

EDITAR

me di cuenta de que mi combinar la macro no era en realidad la combinación de dos variables de 32 bits, sino simplemente la operación lógica OR 0 por una, y conseguir una como resultado.
Por lo tanto, además de mis preguntas anteriores, todavía no tengo un método para combinar las dos variables de 32 bits para obtener una de 64 bits; una sugerencia sobre cómo hacerlo sería apreciada.

+4

+1, pregunta increíble, gracias por tomarse el tiempo para formatearla correctamente y ¡Bienvenido a Stack Overflow! –

+0

Por cierto, apuesto a que su macro combinada se supone que es ORing con b, no una, ¿verdad? – tloflin

Respuesta

18

Sí, es un comportamiento indefinido.

IEC 9899 ISO /: 1999 6.5.7 operadores de desplazamiento a nivel de bit ¶3

Las promociones enteros se realizan en cada uno de los operandos. El tipo de resultado es el del operando izquierdo promovido. Si el valor del operando derecho es negativo o es mayor o igual que el ancho del operando izquierdo promovido, el comportamiento no está definido.

C11 también conocido como ISO/IEC 9899: 2011 dice lo mismo.

Primero debe convertir b al tipo entero de destino. Otro punto es que debe poner paréntesis alrededor de los parámetros de macro para evitar sorpresas por las precedencias del operador. Además, el operador de coma es muy útil aquí, lo que le permite evitar las llaves, por lo que la macro se puede utilizar como un comando normal, cerrado con un punto y coma.

#define splitup(a,b,c) ((b) = (a) >> 32, (c) = (a) & 0xffffffff) 
#define combine(a,b,c) ((a) = ((unsigned long long)(b) << 32) | (c)) 

moldes adicionales pueden ser necesarias para `splitup para silenciar las advertencias acerca de la pérdida de precisión de más paranoico-compiladores.

#define splitup(a,b,c) ((b) = (unsigned long)((a) >> 32), (c) = (unsigned long)((a) & 0xffffffff)) 

Y por favor ni siquiera piense en usar su encriptación auto escrita para el código de producción.

3

¿qué tiene de malo cambiar una variable de 32 bits de 32 bits?

Es mejor asignar 0 a n-bit entero que cambiarlo por n bits.

Ejemplo:

0 0 1 0 1 ----- 5 bit Integer 
0 1 0 1 0 ----- 1st shift 
1 0 1 0 0 ----- 2nd shift 
0 1 0 0 0 ----- 3rd shift 
1 0 0 0 0 ----- 4th shift 
0 0 0 0 0 ----- 5th shift (all the bits are shifted!) 

Todavía no tengo un método de combinación de las dos variables de 32 bits para obtener un 64-bit uno

Considere:a es 64 bit, b y c son 32 bit

a = b; 
a = a << 32; //Note: a is 64 bit 
a = a | c; 
+0

Oh, está bien. Así que mi macro combinada era ORing 0 por a para obtener un; lo cual, si estoy en lo correcto, significa que en realidad no estaba combinando las dos variables de 32 bits para hacer una variable de 64 bits. maldito. – masseyc

0

A menos que esto es un poco de "reinventar la rueda para entender cómo funciona" proyecto, no aplicar sus propias funciones criptográficas.

Ever.

Ya es bastante difícil usar los algoritmos disponibles para trabajar (y elegir el correcto), no te dispares en el pie al poner en producción una API criptadora doméstica. Las posibilidades son your encryption won't encrypt

+3

Gracias por la sugerencia, pero este * es * uno de esos proyectos de "reinvención de la rueda para comprender cómo funciona". :) – masseyc

+0

OK, pero no olvides destruir el código cuando hayas terminado: D – Guillaume

+3

No creo en este consejo. – Joshua

10

Cambiar un valor de 32 bits por 32 bits o más no está definido en C y C++. Una de las razones por las que no se definió es que en algunas plataformas de hardware, la instrucción de desplazamiento de 32 bits solo tiene en cuenta los 5 bits más bajos del recuento de turnos suministrados. Esto significa que sea cual sea el conteo de turnos que pase, se interpretará el módulo 32. Intentar cambiar por 32 en dicha plataforma realmente cambiará por 0, es decir, no cambiará en absoluto.

Los autores del lenguaje no querían agobiar a los compiladores escritos para dicha plataforma con la tarea de analizar el recuento de turnos antes de realizar el turno. En cambio, la especificación del lenguaje dice que el comportamiento no está definido. Esto significa que si desea obtener un valor 0 de un cambio de 32 bits por 32 (o más), depende de usted reconocer la situación y procesarla en consecuencia.

+6

Probablemente vale la pena señalar que "algunas plataformas" en este caso incluyen x86. – caf

+0

increíble ... los compiladores deberían "compensar" los "límites" de la arquitectura de hardware subyacente ... ¿y si existiera un procesador que no implementa bit shift (impar) en absoluto? el resultado total de >> o << sería indefinido ?! gracioso ... – ShinTakezou

+1

@ShinTakezou: Algunos programas necesitan evaluar 'x << (y & 31)'. A veces los programas necesitan 'y> = 32? 0: x << y'. Algunos estarán igualmente felices con cualquier resultado. Si el Estándar ordenaba cualquier comportamiento, los compiladores de al menos algunas plataformas tendrían que generar código innecesario para los programas que no les importaba el resultado que recibían. Peor aún, cuando los programas que necesitan el tipo de resultado opuesto se ejecutan en plataformas que devolverían "naturalmente" lo que el programa quería, los programadores tendrían que escribir código para superar los efectos del código adicional no deseado introducido por el compilador. – supercat

0

¿Qué tiene de malo cambiar una variable de 32 bits de 32 bits?

Además de lo que se ha dicho ya, el bit 32 es el bit de signo, y es posible obtener extensión de signo para preservar el cante, perdiendo así bits significativos.

Cuestiones relacionadas