internal void EstableceSecreto(Buzon secreto) { Depuracion.Asevera(Seguridad.longitud_secreto == CifradoAES.BytesClave); Depuracion.Asevera(CifradoAES.BytesClave == CalculoHMAC.BytesValor); // if (cifrado_AES_local != null) { cifrado_AES_local.Termina(); } cifrado_AES_local = new CifradoAES(); if (cifrado_AES_remoto != null) { cifrado_AES_remoto.Termina(); } cifrado_AES_remoto = new CifradoAES(); if (calculo_HMAC_local != null) { calculo_HMAC_local.Termina(); } calculo_HMAC_local = new CalculoHMAC(); if (calculo_HMAC_remoto != null) { calculo_HMAC_remoto.Termina(); } calculo_HMAC_remoto = new CalculoHMAC(); // EstableceSecreto(secreto, true, true, "clave_encripta_cliente"); EstableceSecreto(secreto, true, false, "clave_encripta_servicio"); EstableceSecreto(secreto, false, true, "clave_autentica_cliente"); EstableceSecreto(secreto, false, false, "clave_autentica_servicio"); }
internal MensajeInicio(Seguridad seguridad_) : base(seguridad_) { Depuracion.Asevera(!seguridad_.DeServidor); // Prepara(); }
/// <summary> /// Calcula el código HMAC del mensaje y lo deja en el buzón indicado. /// </summary> /// <remarks> /// El buzón 'valor_HMAC' puede ser vacío; en ese caso se crea un array de bytes de longitud /// 'BytesValor' y se encapsula en el buzón. Si 'valor_HMAC' no es vacío, su longitud debe /// ser 'BytesValor'. /// </remarks> /// <param name="mensaje">Mensaje para el que se calcula el código HMAC.</param> /// <param name="valor_HMAC">Código HMAC calculado, de longitud BytesValor.</param> internal void Calcula(Buzon mensaje, Buzon valor_HMAC) { #if DEBUG Depuracion.Asevera(algoritmo != null); Depuracion.Asevera(mensaje != null); Depuracion.Asevera(mensaje.Longitud > 0); Depuracion.Asevera(valor_HMAC != null); if (valor_HMAC.Longitud > 0) { Depuracion.Asevera(valor_HMAC.Longitud == BytesValor); } #endif // byte [] retorno = algoritmo.ComputeHash(mensaje.Datos, mensaje.Inicio, mensaje.Longitud); // #if DEBUG Depuracion.Asevera(retorno.Length == BytesValor); #endif // if (valor_HMAC.Longitud == 0) { valor_HMAC.Construye(retorno); } else { Buffer.BlockCopy(retorno, 0, valor_HMAC.Datos, valor_HMAC.Inicio, BytesValor); } }
/// <summary> /// Prepara la instancia para realizar los cálculos, estableciendo la clave de /// autenticación. /// </summary> /// <remarks> /// 'clave_SHA' puede ser de cualquier tamaño, pero el recomendado es 64 bytes. /// Cada llamada a 'Inicia' debe tener la correspondiente llamada a 'Termina' (en un 'try', /// 'finally'). /// </remarks> /// <param name="clave_SHA">Clave de autenticación, de longitud 'BytesClave'.</param> internal void Inicia(Buzon clave_SHA) { #if DEBUG Depuracion.Asevera(algoritmo == null); Depuracion.Asevera(clave_SHA != null); Depuracion.Asevera(clave_SHA.Longitud > 0); #endif // byte [] entrada; if (clave_SHA.Inicio == 0 && clave_SHA.Datos.Length == clave_SHA.Longitud) { entrada = clave_SHA.Datos; } else { entrada = new byte [clave_SHA.Longitud]; clave_SHA.TomaBinario(0, entrada); } // algoritmo = new HMACSHA256(entrada); // #if DEBUG Depuracion.Asevera(algoritmo.CanReuseTransform); Depuracion.Asevera(algoritmo.CanTransformMultipleBlocks); Depuracion.Asevera(algoritmo.HashSize == BitsValor); #endif }
/// <summary> /// Prepara la instancia para generar los datos aleatorios. /// </summary> /// <remarks> /// Cada llamada a 'Inicia' debe tener la correspondiente llamada a 'Termina' (en un 'try', /// 'finally'). /// </remarks> internal void Inicia() { #if DEBUG Depuracion.Asevera(algoritmo == null); #endif // algoritmo = RandomNumberGenerator.Create(); //new RNGCryptoServiceProvider (); }
/// <summary> /// Genera datos aleatorios y los escribe en el buzón. /// </summary> /// <remarks> /// El numero de bytes generados es igual a la longitud del buzón. /// </remarks> /// <param name="data">Buzón donde se dejarán los datos aleatorios.</param> internal void Genera(Buzon data) { #if DEBUG Depuracion.Asevera(algoritmo != null); Depuracion.Asevera(data != null); Depuracion.Asevera(data.Longitud > 0); #endif // algoritmo.GetBytes(data.Datos); }
// Lee del array del buzón la representación en bytes de un entero corto. // El formato usado es 'big-endian'. // Se leen 2 bytes de la posición indicada, el rango leido debe estar dentro del array // de bytes de la instancia. internal short TomaShort(int posicion) { #if DEBUG Depuracion.Depura(this.almacen == null, "'Buzon' vacío."); ValidaRango(posicion, 2); #endif // int primero = this.inicio + posicion; return((short)(((this.almacen [primero] & 0xff) << 8) | ((this.almacen [primero + 1] & 0xff)))); }
// Escribe en el array del buzón la representación en bytes del número. // El formato usado es 'big-endian'. // Se escriben 2 bytes en la posición indicada, el rango escrito debe estar dentro del array // de bytes de la instancia. internal void PonShort(int posicion, short numero) { #if DEBUG Depuracion.Depura(this.almacen == null, "'Buzon' vacío."); ValidaRango(posicion, 2); #endif // int primero = this.inicio + posicion; this.almacen [primero] = (byte)(numero >> 8); this.almacen [primero + 1] = (byte)(numero); }
// Lee una secuencia de bytes del array del buzón. // Los bytes leidos se escriben en 'binario'. El número de bytes leidos es su longitud, que // no puede ser cero. // Se lee los bytes de la posición indicada, el rango leido debe estar dentro del array de // bytes de la instancia. internal void TomaBinario(int posicion, byte [] binario) { #if DEBUG Depuracion.Depura(this.almacen == null, "'Buzon' vacío."); Depuracion.Depura(binario == null, "'binario' nula"); Depuracion.Depura(binario.Length == 0, "'binario' vacío"); ValidaRango(posicion, binario.Length); #endif // int destino = this.inicio + posicion; Buffer.BlockCopy(this.almacen, destino, binario, 0, binario.Length); }
// Reserva memoria para un array de bytes de la longitud indicada y lo encapsula en la instancia. // La instancia debe estar previamente vacía. internal void Reserva(int longitud_) { #if DEBUG Depuracion.Depura(this.almacen != null, "'Buzon' no vacío"); Depuracion.Depura(longitud_ <= 0, "'longitud_' inválida."); #endif // this.almacen = new byte [longitud_]; this.inicio = 0; this.longitud = longitud_; this.porciones = 0; }
/// <summary> /// Incrementa el número de bloque usado en los contadores. Cada bloque de un mensaje debe /// ser distinto. /// </summary> /// <remarks> /// El contador queda preparado para ser leido (con 'AsignaContador'). /// </remarks> internal void IncrementaBloque() { Depuracion.Asevera(serie_iniciada); Depuracion.Asevera(contador_leido); Depuracion.Asevera(0 <= numero_bloque && numero_bloque < MaximoBloque); // numero_bloque++; // //PonNumeroBuzon (numero_bloque, inicio_bloque); // contador_leido = false; }
// Lee del array del buzón la representación en bytes de un entero. // El formato usado es 'big-endian'. // Se leen 4 bytes de la posición indicada, el rango leido debe estar dentro del array // de bytes de la instancia. internal int TomaInt(int posicion) { #if DEBUG Depuracion.Depura(this.almacen == null, "'Buzon' vacío."); ValidaRango(posicion, 4); #endif // int primero = this.inicio + posicion; return(((this.almacen [primero]) << 24) | ((this.almacen [primero + 1] & 0xff) << 16) | ((this.almacen [primero + 2] & 0xff) << 8) | ((this.almacen [primero + 3] & 0xff))); }
// Encapsula en esta instancia el array de bytes indicado. // No se debe encapsular el mismo array de bytes en dos instancias distintas. Para ello // están las porciones. // La instancia debe estar previamente vacía. 'datos' no puede tener longitud cero. internal void Construye(byte [] datos) { #if DEBUG Depuracion.Depura(this.almacen != null, "'Buzon' no vacío"); Depuracion.Depura(datos == null, "'datos' nulo."); Depuracion.Depura(datos.Length == 0, "Longitud de 'datos' inválida."); #endif // this.almacen = datos; this.inicio = 0; this.longitud = datos.Length; this.porciones = 0; }
/// <summary> /// Copia el contador en el lugar indicado. /// </summary> /// <remarks> /// El contador debe estar preprado para ser leido. Esto se hace con 'IniciaSerie', /// 'IncrementaMensaje' o 'IncrementaBloque'. Tras copiarlo (con este método) el contador /// deja de estar preparado para ser leido. /// El buzón donde se copia el contador debe ser de longitud 'BytesContador'. /// </remarks> /// <param name="destino">Buzón donde se copiará en contador.</param> internal void AsignaContador(Buzon destino) { Depuracion.Asevera(destino != null); Depuracion.Asevera(destino.Longitud == BytesContador); Depuracion.Asevera(serie_iniciada); Depuracion.Asevera(!contador_leido); // PonNumeroBuzon(numero_serie, inicio_serie, destino); PonNumeroBuzon(numero_mensaje, inicio_mensaje, destino); PonNumeroBuzon(numero_bloque, inicio_bloque, destino); //Buffer.BlockCopy (buzon_contador, 0, destino.Datos, destino.Inicio, BytesContador); // contador_leido = true; }
// Reserva memoria para un array de bytes, lo encapsula en la instancia y copia el array de // bytes 'datos' en él. // La instancia debe estar previamente vacía. 'datos' no puede tener longitud cero. internal void ReservaYCopia(byte [] datos) { #if DEBUG Depuracion.Depura(this.almacen != null, "'Buzon' no vacío"); Depuracion.Depura(datos == null, "'datos' nulo."); Depuracion.Depura(datos.Length == 0, "Longitud de 'datos' inválida."); #endif // this.almacen = new byte [datos.Length]; this.inicio = 0; this.longitud = datos.Length; this.porciones = 0; // Buffer.BlockCopy(datos, 0, this.almacen, 0, datos.Length); }
// Asigna 0 a los bytes del array encapsulado en esta instancia. // Esta instancia no puede ser vacía. internal void Blanquea() { #if DEBUG Depuracion.Depura(this.almacen == null, "'Buzon' vacío."); #endif // int indice = this.inicio; int longitud_ = this.longitud; while (longitud_ > 0) { this.almacen [indice] = 0; indice++; longitud_--; } }
/// <summary> /// Establece los primeros números a ser usados en los contadores. /// </summary> /// <remarks> /// Establece el número de serie 0, el número de mensaje 0 y el número de bloque 0. Se usa /// solo la primera vez que se cambia la serie, para las siguientes se usa 'CambiaSerie'. /// El contador queda preparado para ser leido (con 'AsignaContador'). /// </remarks> /// <param name="serie">marca de la nueva serie, </param> internal void Inicia() { Depuracion.Asevera(!serie_iniciada); // numero_serie = 0; numero_mensaje = 0; numero_bloque = 0; // //PonNumeroBuzon (numero_serie, inicio_serie); //PonNumeroBuzon (numero_mensaje, inicio_mensaje); //PonNumeroBuzon (numero_bloque, inicio_bloque); // serie_iniciada = true; contador_leido = false; }
// Reserva memoria para un array de bytes, lo encapsula en la instancia y escribe la cadena de // caracteres en él. // Cada caracter de 'datos' se escribe en dos bytes del array, el formato usado es // 'big-endian'. Por tanto, la longitud del array de bytes es el doble que la de la cadena // de caracteres. // La instancia debe estar previamente vacía. 'datos' no puede tener longitud cero. internal void ReservaYCopia(string cadena) { #if DEBUG Depuracion.Depura(this.almacen != null, "'Buzon' no vacío"); Depuracion.Depura(cadena == null, "'cadena' nulo."); Depuracion.Depura(cadena.Length == 0, "Longitud de 'cadena' inválida."); #endif // this.almacen = new byte [cadena.Length * 2]; this.inicio = 0; this.longitud = cadena.Length * 2; this.porciones = 0; // PonString(0, cadena); }
// Tansforma un buzón en una porción que encapsula un rango del array de bytes de esta // intancia. // El buzón a transformar, 'porcion', debe estar vacío. // La instancia no puede estar vacía ni ser una porción de otro buzón. 'inicio' y // 'longitud' deben designar un rango válido en el array de bytes. // En la instancia queda anotado que hay una porción mas creada sobre ella. internal void ConstruyePorcion(int posicion, int longitud, Buzon porcion) { #if DEBUG Depuracion.Depura(this.almacen == null, "'Buzon' vacío."); Depuracion.Depura(this.porciones < 0, "Este es porcion de otro 'Buzon'."); ValidaRango(posicion, longitud); Depuracion.Depura(porcion == null, "'porcion' nulo."); Depuracion.Depura(porcion.almacen != null, "'porcion' no vacío."); #endif // porcion.almacen = this.almacen; porcion.inicio = posicion; porcion.longitud = longitud; porcion.porciones = -1; this.porciones++; }
/// <summary> /// Pone a cero el número de mensaje usado en los contadores. Se pone a cero para cambiar la /// clave de encriptación y la serie. /// </summary> /// <remarks> /// El número de serie y el número de bloque pasan a ser 0. /// Solo se puede usar este método cuando el número de serie y el número de mensaje no es 0. /// El contador queda preparado para ser leido (con 'AsignaContador'). /// </remarks> internal void AnulaMensaje() { Depuracion.Asevera(serie_iniciada); // se anula el mensaje tras cambiar la serie, cuando el contador no está leido: //Depuracion.Asevera (contador_leido); Depuracion.Asevera(numero_serie != 0); Depuracion.Asevera(numero_mensaje > 0); // numero_mensaje = 0; numero_bloque = 0; // //PonNumeroBuzon (numero_mensaje, inicio_mensaje); //PonNumeroBuzon (numero_bloque, inicio_bloque); // contador_leido = false; }
// Escribe en el array del buzón la representación en bytes del número. // El formato usado es 'big-endian'. // Se escriben 8 bytes en la posición indicada, el rango escrito debe estar dentro del array // de bytes de la instancia. internal void PonLong(int posicion, long numero) { #if DEBUG Depuracion.Depura(this.almacen == null, "'Buzon' vacío."); ValidaRango(posicion, 8); #endif // int primero = this.inicio + posicion; this.almacen [primero] = (byte)(numero >> 56); this.almacen [primero + 1] = (byte)(numero >> 48); this.almacen [primero + 2] = (byte)(numero >> 40); this.almacen [primero + 3] = (byte)(numero >> 32); this.almacen [primero + 4] = (byte)(numero >> 24); this.almacen [primero + 5] = (byte)(numero >> 16); this.almacen [primero + 6] = (byte)(numero >> 8); this.almacen [primero + 7] = (byte)(numero); }
// Lee del array del buzón la representación en bytes de un entero largo. // El formato usado es 'big-endian'. // Se leen 8 bytes de la posición indicada, el rango leido debe estar dentro del array // de bytes de la instancia. internal long TomaLong(int posicion) { #if DEBUG Depuracion.Depura(this.almacen == null, "'Buzon' vacío."); ValidaRango(posicion, 8); #endif // int primero = this.inicio + posicion; return(((((long)this.almacen [primero])) << 56) | ((((long)this.almacen [primero + 1]) & 0xff) << 48) | ((((long)this.almacen [primero + 2]) & 0xff) << 40) | ((((long)this.almacen [primero + 3]) & 0xff) << 32) | ((((long)this.almacen [primero + 4]) & 0xff) << 24) | ((((long)this.almacen [primero + 5]) & 0xff) << 16) | ((((long)this.almacen [primero + 6]) & 0xff) << 8) | ((((long)this.almacen [primero + 7]) & 0xff))); }
// Escribe la cadena de caracteres en el array del buzón. // Cada caracter se escribe en dos bytes del array, el formato usado es 'big-endian'. Por // tanto, el número de bytes escritos es el doble de la longitud de la cadena de caracteres. // Se escriben los bytes en la posición indicada, el rango escrito debe estar dentro del // array de bytes de la instancia. internal void PonString(int posicion, string cadena) { #if DEBUG Depuracion.Depura(this.almacen == null, "'Buzon' vacío."); Depuracion.Depura(cadena == null, "'cadena' nula"); ValidaRango(posicion, cadena.Length * 2); #endif // int destino = this.inicio + posicion; for (int indice = 0; indice < cadena.Length; ++indice) { char caracter = cadena [indice]; this.almacen [destino] = (byte)(caracter >> 8); this.almacen [destino + 1] = (byte)(caracter); destino += 2; } }
// Libera la memoria usada por esta instancia, dejandola vacía. // Esta instancia no puede ser una porción, ni debe haber porciones de esta instancia. internal void Libera() { if (this.almacen == null) { return; } // #if DEBUG // no actua en buzón vacío Depuracion.Depura(this.porciones < 0, "Este es porcion de otro 'Buzon'."); Depuracion.Depura(this.porciones > 0, "Quedan porciones de este 'Buzon'."); #endif // this.almacen = null; this.inicio = 0; this.longitud = 0; this.porciones = 0; }
// Devuelve y asigna un byte del array encapsulado, el situado en la posicion indicada. // Su es una porción, se toma la posición a partir del inicio de la porción. // No puede ser una instancia vacía. internal byte this [int posicion] { get { #if DEBUG Depuracion.Depura(this.almacen == null, "'Buzon' vacío."); ValidaRango(posicion, 1); #endif // return(this.almacen [this.inicio + posicion]); } set { #if DEBUG Depuracion.Depura(this.almacen == null, "'Buzon' vacío."); ValidaRango(posicion, 1); #endif // this.almacen [this.inicio + posicion] = value; } }
internal void Envia(int longitud) { Depuracion.Depura(de_servidor, "me he hecho un lío"); Depuracion.Depura(longitud != conexion.BuzonPaquete.Longitud, "me he hecho un lío"); // if (contador_CTR_local.NumeroSerie == 0 && contador_CTR_local.NumeroMensaje == 0) { // Depuracion.Depura(!de_cliente, "'billete' o 'indice' fuera de lugar"); // MensajeInicio mensaje_claves = new MensajeInicio(this); mensaje_claves.Envia(); // MensajeSeguridad mensaje_billete = new MensajeSeguridad(this, MensajeSeguridad.Tipologia.Inicio); mensaje_billete.RecibeBillete(); // } // TimeSpan tiempo = DateTime.Now - contador_tiempo; if (contador_bytes > 200 || tiempo.TotalMinutes > 20) { contador_CTR_local.AnulaMensaje(); contador_CTR_remoto.AnulaMensaje(); } // if (contador_CTR_local.NumeroMensaje == 0) { // MensajeSeguridad mensaje_seguridad = new MensajeSeguridad(this, MensajeSeguridad.Tipologia.Secreto); mensaje_seguridad.EnviaSecreto(); // MensajeSeguridad mensaje_billete = new MensajeSeguridad(this, MensajeSeguridad.Tipologia.Billete); mensaje_billete.RecibeBillete(); // } // mensaje_general.Envia(); }
// Anula una porción de esta instancia, dejandola vacía. // El buzón anulado ('porcion') debe ser una porción previamente construida sobre esta // instancia. // En la instancia queda anotado que hay una porción menos creada sobre ella. internal void AnulaPorcion(Buzon porcion) { #if DEBUG Depuracion.Depura(this.almacen == null, "'Buzon' vacío."); Depuracion.Depura(this.porciones < 0, "Este es porcion de otro 'Buzon'."); Depuracion.Depura(this.porciones == 0, "Este no tiene porciones."); Depuracion.Depura(porcion == null, "'porcion' nulo"); Depuracion.Depura(porcion.almacen == null, "'porcion' vacío"); Depuracion.Depura(porcion.porciones >= 0, "'porcion' no es un porcion'"); Depuracion.Depura(porcion.almacen != this.almacen, "'porcion' no es porcion de este"); #endif // porcion.almacen = null; porcion.inicio = 0; porcion.longitud = 0; porcion.porciones = 0; this.porciones--; }
// Lee una serie de caracteres del array del buzón y los escribe en una cadena caracteres. // Cada caracter de se lee de dos bytes del array, el formato usado es 'big-endian'. // El número de caracteres leidos es 'longitud_' y el número de bytes leidos es el doble. // Se lee los bytes de la posición indicada, el rango leido debe estar dentro del array de // bytes de la instancia. // Antes de escribir los caracteres en 'cadena', esta se vacía. internal void TomaString(int posicion, int longitud_, StringBuilder cadena) { #if DEBUG Depuracion.Depura(this.almacen == null, "'Buzon' vacío."); Depuracion.Depura(cadena == null, "'cadena' nula"); ValidaRango(posicion, longitud_ * 2); #endif // cadena.Length = 0; int indice = this.inicio + posicion; for (int cuenta = 0; cuenta < longitud_; ++cuenta) { char caracter = (char)(((this.almacen [indice] & 0xff) << 8) | ((this.almacen [indice + 1] & 0xff))); cadena.Append(caracter); indice += 2; } }
internal void Recibe() { Depuracion.Depura(de_servidor, "me he hecho un lío"); // if (contador_CTR_local.NumeroSerie == 0 && contador_CTR_local.NumeroMensaje == 0) { Depuracion.Depura(!de_servicio, "'billete' o 'indice' fuera de lugar"); // MensajeInicio mensaje_claves = new MensajeInicio(this); mensaje_claves.Recibe(); // MensajeSeguridad mensaje_billete = new MensajeSeguridad(this, MensajeSeguridad.Tipologia.Inicio); mensaje_billete.EnviaBillete(); } // int indice; mensaje_general.RecibeCabecera(out indice); // if (indice == 0) { // contador_CTR_local.AnulaMensaje(); contador_CTR_remoto.AnulaMensaje(); // MensajeSeguridad mensaje_seguridad = new MensajeSeguridad(this, MensajeSeguridad.Tipologia.Secreto); mensaje_seguridad.IntegraCabecera(mensaje_general); mensaje_seguridad.RecibeSecreto(); // MensajeSeguridad mensaje_billete = new MensajeSeguridad(this, MensajeSeguridad.Tipologia.Billete); mensaje_billete.EnviaBillete(); // mensaje_general.RecibeCabecera(out indice); // } // mensaje_general.RecibeCuerpo(); }
// Copia una parte del array de bytes de un buzón en otro buzón. // El rango de bytes a copiar, tanto en 'origen' como en 'destino', es de 0 a 'longitud_'-1. // El rango debe ser válido en ambos buzones. // Los buzones puede ser porciones (uno o los dos). En tal caso, el rango a copiar se toma // dentro del rango de la porción. internal static void CopiaDatos(Buzon origen, Buzon destino, int longitud_) { #if DEBUG Depuracion.Depura(origen == null, "'origen' nulo"); Depuracion.Depura(destino == null, "'destino' nulo"); Depuracion.Depura(origen.almacen == null, "'origen' vacío"); Depuracion.Depura(destino.almacen == null, "'destino' vacío"); origen.ValidaRango(0, longitud_); destino.ValidaRango(0, longitud_); #endif // int indice_origen = origen.inicio; int indice_destino = destino.inicio; while (longitud_ > 0) { destino.almacen [indice_destino] = origen.almacen [indice_origen]; indice_origen++; indice_destino++; longitud_--; } }