# Utilización de técnicas de programación segura:
 -	Prácticas de programación segura.
 -	Criptografía de clave pública y clave privada.
 -	Principales aplicaciones de la criptografía.
 -	Protocolos criptográficos.
 -	Política de seguridad.
 -	Programación de mecanismos de control de acceso.
 -	Encriptación de información.
 -	Protocolos seguros de comunicaciones.
 -	Programación de aplicaciones con comunicaciones seguras.

# CCN-STIC-807 – Criptografía de empleo en el ENS
|Tipo de Algoritmo| Acreditados por el CCN|
|--|--
|Cifrado Simétrico|TDEA (Triple Data Encryption Algorithm)
||AES (Advanced Encryption Standard)
|Algoritmos Asimétricos|DSA (Digital Signature Algorithm)
||ECDSA (Elliptic Curve Digital Signature Algorithm)
||RSA (Criptosistema RSA)
||ECIES (Elliptic Curve Integrated Encryption Scheme)
|Intercambio de Clave|DH o DHKA (Diffie-Hellman Key Agreement)
||MQV (Menezes-Qu-Vanstone Key Agreement)
||ECDH (Elliptic Curve Diffie-Hellman)
||ECMQV (Elliptic Curve Menezes-Qu-Vanstone)
|Funciones resumen (Hash)|SHA-2 (Secure Hash Algorithm)
||HMAC (Hash Message Authentication Code )

# Cifrado
## Cifrado simétrico
- TDEA (Triple Data Encryption Algorithm)
- AES (Advanced Encryption Standard)

```Java
/* Con clave aleatoria */

import javax.crypto.*;    
import java.security.*;  

public class Java {

	private static SecretKey key = null;         
	private static Cipher cipher = null; 

	public static void main(String[] args) throws Exception
	{
		KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
		keyGenerator.init(128);
		SecretKey secretKey = keyGenerator.generateKey();
		cipher = Cipher.getInstance("AES");

		String clearText = "hola";
		byte[] clearTextBytes = clearText.getBytes("UTF8");
		System.out.println("Texto en claro: " + clearText);
		System.out.println("Texto en Bytes claro: " + clearTextBytes);

		cipher.init(Cipher.ENCRYPT_MODE, secretKey);
		byte[] cipherBytes = cipher.doFinal(clearTextBytes);
		String cipherText = new String(cipherBytes, "UTF8");
		System.out.println("Texto cifrado: " + cipherText);
		System.out.println("Texto en Bytes cifrado: " + cipherBytes);

		cipher.init(Cipher.DECRYPT_MODE, secretKey);
		byte[] decryptedBytes = cipher.doFinal(cipherBytes);
		String decryptedText = new String(decryptedBytes, "UTF8");
		System.out.println("Texto descifrado: " + decryptedText);
		System.out.println("Texto en Bytes cifrado: " + decryptedBytes);
	}
}
```

```Java
/* Con clave añadida*/

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.util.Base64;

public class Java {

	private static Cipher cipher = null; 

	public static void main(String[] args) throws Exception{
		// Clave -> Clave en base 64
		// 1234567891234567 -> MTIzNDU2Nzg5MTIzNDU2Nw==
		// decode the base64 encoded string
		byte[] decodedKey = Base64.getDecoder().decode("MTIzNDU2Nzg5MTIzNDU2Nw==");
		
		// rebuild key using SecretKeySpec
		SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
		System.out.println("originalKey: " + decodedKey);
		
		cipher = Cipher.getInstance("AES");

		String clearText = "hola";
		byte[] clearTextBytes = clearText.getBytes("UTF8");
		System.out.println("Texto en claro: " + clearText);

		cipher.init(Cipher.ENCRYPT_MODE, originalKey);
		byte[] cipherBytes = cipher.doFinal(clearTextBytes);
		String cipherText = new String(cipherBytes, "UTF8");
		System.out.println("Texto cifrado: " + cipherText);

		cipher.init(Cipher.DECRYPT_MODE, originalKey);
		byte[] decryptedBytes = cipher.doFinal(cipherBytes);
		String decryptedText = new String(decryptedBytes, "UTF8");
		System.out.println("Texto descifrado: " + decryptedText);
	}
}
```

## Algoritmos asimétricos
- DSA (Digital Signature Algorithm)
- ECDSA (Elliptic Curve Digital Signature Algorithm)
- RSA (Criptosistema RSA)

```Java
import javax.crypto.*;
import java.security.*;
public class ExampleRSA {

	public static void main(String[] args) {
		try {
			KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
			KeyPair keypair = keygen.generateKeyPair();
			
			Cipher rsaCipher = Cipher.getInstance("RSA");
			
			String mensaje = "Mensajeo";
			
			rsaCipher.init(Cipher.ENCRYPT_MODE, keypair.getPrivate());
			byte[] mensajeCifrado = rsaCipher.doFinal(mensaje.getBytes("UTF8"));
			System.out.println(mensajeCifrado);
			
			rsaCipher.init(Cipher.DECRYPT_MODE, keypair.getPublic());
			byte[] mensajeDescifrado = rsaCipher.doFinal(mensajeCifrado);
			String mensajeDescifrado2 = new String(mensajeDescifrado, "UTF8");
			System.out.println(mensajeDescifrado2);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
```

- ECIES (Elliptic Curve Integrated Encryption Scheme)

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

# Ejemplos
## Cifrar y descrifrar con clave secreta

```Java
import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;


public class Ejemplo10 {
	public static void main(String args[]) {
		try {
			//ALGORITMO DES
			KeyGenerator kg = KeyGenerator.getInstance("DES");
			Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");
			Key key = kg.generateKey();
			
			c.init(Cipher.ENCRYPT_MODE, key);
			byte input[] = "Stand and unfold yourself".getBytes();
			byte encrypted[] = c.doFinal(input);
			byte iv[] = c.getIV();

			IvParameterSpec dps = new IvParameterSpec(iv);
			c.init(Cipher.DECRYPT_MODE, key, dps);
			byte output[] = c.doFinal(encrypted);
			System.out.println("The string was ");
			System.out.println(new String(output));
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		//ALGORITMO AES
		try {
			KeyGenerator kg = KeyGenerator.getInstance("AES");
			kg.init (128);
			SecretKey clave = kg.generateKey();
			
			Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
			c.init(Cipher.ENCRYPT_MODE, clave);
				
			//CIFRAMOS TEXTO
			byte textoPlano[] = "Esto es un Texto Plano".getBytes();
			byte textoCifrado[] = c.doFinal(textoPlano);
			System.out.println("Encriptado: "+ new String(textoCifrado));
			
		    //DESCIFRAMOS TEXTO					
			c.init(Cipher.DECRYPT_MODE, clave);		
			byte desencriptado[] = c.doFinal(textoCifrado);
			System.out.println("Desencriptado: "+ new String(desencriptado));
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
}
```

## Cifrar y descifrar con clave pública

```Java
import java.security.*;
import javax.crypto.*;

public class Ejemplo11 {
	public static void main(String args[]) {
		
		try {
			//SE CREA EL PAR DE CLAVES		
			KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
			keyGen.initialize (1024);
			KeyPair par = keyGen.generateKeyPair();
			PrivateKey clavepriv = par.getPrivate();
			PublicKey clavepub = par.getPublic();
			
		
			Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			c.init(Cipher.ENCRYPT_MODE, clavepub);

			//CIFRAMOS TEXTO
			byte textoPlano[] = "Esto es un Texto Plano".getBytes();
			byte textoCifrado[] = c.doFinal(textoPlano);
			System.out.println("Encriptado: "+ new String(textoCifrado));
			
		    //DESCIFRAMOS TEXTO					
			c.init(Cipher.DECRYPT_MODE, clavepriv);		
			byte desencriptado[] = c.doFinal(textoCifrado);
			System.out.println("Desencriptado: "+ new String(desencriptado));

		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
}
```

## Cifrar y descifrar con clave pública

```Java
import java.security.*;
import javax.crypto.*;
public class Ejemplo12 {
	public static void main(String args[]) {		
		try {
			//SE CREA EL PAR DE CLAVES publica y privada	
			KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
			keyGen.initialize (1024);
			KeyPair par = keyGen.generateKeyPair();
			PrivateKey clavepriv = par.getPrivate();
			PublicKey clavepub = par.getPublic();			
		
			//SE CREA LA CLAVE SECRETA AES 
			KeyGenerator kg = KeyGenerator.getInstance("AES");
			kg.init (128);
			SecretKey clavesecreta = kg.generateKey();
			
			//SE ENVUELVE LA CLAVE SECRETA CON LA RSA PÚBLICA					
			Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			c.init(Cipher.WRAP_MODE, clavepub);
			byte claveenvuelta[] = c.wrap(clavesecreta);				
			
			//CIFRAMOS TEXTO CON LA CLAVE SECRETA
			c = Cipher.getInstance("AES/ECB/PKCS5Padding");
			c.init(Cipher.ENCRYPT_MODE, clavesecreta);			
			byte textoPlano[] = "Esto es un Texto Plano".getBytes();
			byte textoCifrado[] = c.doFinal(textoPlano);
			System.out.println("Encriptado: "+ new String(textoCifrado));						
			
		    //SE DESENVUELVE LA CLAVE SECRETA CON LA CLAVE RSA PRIVADA	
			Cipher c2 = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			c2.init(Cipher.UNWRAP_MODE, clavepriv);
			Key clavedesenvuelta= c2.unwrap(claveenvuelta, "AES", Cipher.SECRET_KEY);
			
			//DESCIFRAMOS TEXTO CON LA CLAVE DESENVUELTA
			c2 = Cipher.getInstance("AES/ECB/PKCS5Padding");
			c2.init(Cipher.DECRYPT_MODE, clavedesenvuelta);		
			byte desencriptado[] = c2.doFinal(textoCifrado);
			System.out.println("Desencriptado: "+ new String(desencriptado));

		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}//main
}//..Ejemplo12
```

## Almacenar la clave secreta en un fichero

```Java
import java.io.*;
import java.security.*;
import javax.crypto.*;

public class AlmacenaClaveSecreta {
   public static void main(String[] args) {
	try {
		KeyGenerator kg = KeyGenerator.getInstance("AES");
		kg.init(128);

        //genera clave secreta
		SecretKey clave = kg.generateKey();

		ObjectOutputStream out = new ObjectOutputStream(
				       new FileOutputStream("Clave.secreta"));
		out.writeObject(clave);
		out.close();
	} catch (NoSuchAlgorithmException e) {e.printStackTrace();} 
	  catch (FileNotFoundException e) {e.printStackTrace();} 
	  catch (IOException e) {e.printStackTrace();}
   }//main
}//..AlmacenaClaveSecreta
```

## Utilizar la clave secreta almacenada en un fichero para cifrar un documento PDF de nombre FICHERO.pdf

```Java
import java.io.*;
import java.security.*;
import javax.crypto.*;

public class Ejemplo13Cifra {
	public static void main(String[] args) {
		try {	
			//RECUPERAMOS CLAVE SECRETA DEL FICHERO
			ObjectInputStream oin = new ObjectInputStream(
					 new FileInputStream("Clave.secreta"));
	        Key clavesecreta = (Key) oin.readObject();
	        oin.close();	        
			//SE DEFINE EL OBJETO Cipher
			Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
			c.init(Cipher.ENCRYPT_MODE, clavesecreta);
			//FICHERO A CIFRAR
			FileInputStream filein = new FileInputStream("FICHERO.pdf");
			
			//OBJETO CipherOutputStream
			CipherOutputStream out = new CipherOutputStream(
					new FileOutputStream("FicheroPDF.Cifrado"), c);
			int tambloque = c.getBlockSize();
			byte[] bytes = new byte[tambloque];
			
			//LEEMOS BLOQUES DE BYTES DEL FICHERO PDF 
			//Y LO VAMOS ESCRIBIENDO AL CipherOutputStream
			int i = filein.read(bytes);		
			while (i != -1) {				
				out.write(bytes, 0, i);
				i = filein.read(bytes);
			}
			out.flush();
			out.close();
			filein.close(); 
			System.out.println("Fichero cifrado con clave secreta.");		
						
		} catch (Exception e) {
			e.printStackTrace();
		}
	}//main
}//.. Ejemplo13Cifra
```

## Leer y descifrar datos de un fichero cifrado
```Java
import java.io.*;
import java.security.*;
import javax.crypto.*;
public class Ejemplo13Descifra {
	public static void main(String[] args) {
		try {
			//RECUPERAMOS CLAVE SECRETA DEL FICHERO
			ObjectInputStream oin = new ObjectInputStream(
					 new FileInputStream("Clave.secreta"));
	        Key clavesecreta = (Key) oin.readObject();
	        oin.close();	
	        //			
			Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
			c.init(Cipher.DECRYPT_MODE, clavesecreta);
			
			CipherInputStream in = new CipherInputStream(
			      new FileInputStream("FicheroPDF.Cifrado"), c);
			
			int tambloque = c.getBlockSize();
			byte[] bytes = new byte[tambloque];
			
			int i = in.read(bytes);		
			FileOutputStream fileout = new FileOutputStream("FICHEROdescifrado.pdf");
		
			while (i != -1)	{
			  fileout.write(bytes, 0, i);
			  i = in.read(bytes);	
			}		
			fileout.close();
			in.close(); 
			System.out.println("Fichero descifrado con clave secreta.");		
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}//main
}//.. Ejemplo13Descifra
```
