• No se han encontrado resultados

Capítulo 13. Planos de código

N/A
N/A
Protected

Academic year: 2021

Share "Capítulo 13. Planos de código"

Copied!
111
0
0

Texto completo

(1)

Capítulo 13. Planos de código

Este capítulo presenta el código de las clases e interfaces que componen el proyecto. En primer lugar se detallan las clases correspondientes al subsistema de firma, seguidamente se muestra el código de la clase que forma el subsistema de validación y para terminar podemos observar la composición del API de firma del que hacen uso ambos subsistemas.

13.1 Subsistema de firma

El subsistema de firma está compuesto por las clases Firmar y FirmaXML cuyo código se puestra a continuación:

Firmar.java

/*

* Firmar.java *

* Autor: Miguel Castanedo Doña */ import castanedo.xml.crypto.dsig.stax.GeneradorSalida; import castanedo.xml.crypto.dsig.stax.DatosFirma; import castanedo.xml.crypto.dsig.SignedInfoClase; import castanedo.xml.crypto.dsig.XMLSignContextClase; import java.util.ArrayList; import castanedo.xml.crypto.dsig.Firma;

/** Clase que contiene el método main.

* Su ejecución, pasándole los parámetros necesarios

* documento de entrada, documento de salida y formato de firma * provoca la generación del documento firmado.*/

public class Firmar {

/**Método principal para firmar. Comprueba que los parámetros de entrada * sean correctos y desencadena el proceso de firma */

public static void main(String[] args) {

long inicial = System.currentTimeMillis(); String docentrada = "";

String docsalida = ""; String idFirmado = ""; String formato = "";

if (args.length == 3 || args.length == 4) {

docentrada = args[0]; // Primer parámetro: Documento de // entrada

docsalida = args[1]; // Segundo parámetro: Documento de // salida

(2)

if (args.length == 4)

idFirmado = args[3]; // Cuarto parámetro: id del emento

// a firmar si existe.

if (formato.equals(Firma.ENVELOPED)

|| formato.equals(Firma.ENVELOPING) || formato.equals(Firma.DETACHED)) { FirmaXML fxml = new FirmaXML();

SignedInfoClase sigin = fxml.creaSignedInfo(formato, docentrada, idFirmado, docsalida);

if (sigin != null) {

// Se toma una clave cualquiera

byte[] clavebyte = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12, 13, 14, 15 };

XMLSignContextClase sigctxt = fxml.

crearContexto(clavebyte);

// Información de firma. Se crea sin parámetros // pues no son necesarios.

ArrayList listakey = new ArrayList(); listakey.add("CLAVE SIN PARAMETROS");

DatosFirma df = fxml.crearFirma(sigin, sigctxt, listakey,formato);

if (formato.equals(Firma.ENVELOPING)) {

// Se genera el documento de salida // incluyendo los valores de la firma

GeneradorSalida gsalida = new GeneradorSalida( docentrada, docsalida, df); gsalida.escribirDatos(formato); } } } else { System.out

.println("El formato de firma especificado no es válido"); System.out .println("Posibles valores:\nenveloped\nenveloping\ndetached"); } } else { System.out

.println("El número de parámetros introducido no es correcto");

}

long fin = System.currentTimeMillis();

(3)

System.out.println("Tiempo empleado en la firma:" + String.valueOf(total) + " ms"); } } FirmaXML.java /* * FirmaXML.java *

* Autor: Miguel Castanedo Doña */ import castanedo.xml.crypto.dsig.Firma; import castanedo.xml.crypto.dsig.XMLSignContext; import castanedo.xml.crypto.dsig.XMLSignContextClase; import castanedo.xml.crypto.dsig.SignedInfo; import castanedo.xml.crypto.dsig.XMLSignatureClase; import castanedo.xml.crypto.dsig.Reference; import castanedo.xml.crypto.dsig.SignatureMethod; import castanedo.xml.crypto.dsig.CanonicalizationMethod; import castanedo.xml.crypto.dsig.SignatureMethodClase; import castanedo.xml.crypto.dsig.SignedInfoClase; import castanedo.xml.crypto.dsig.DigestMethod; import castanedo.xml.crypto.dsig.ReferenceClase; import castanedo.xml.crypto.dsig.TransformClase; import castanedo.xml.crypto.dsig.Transform; import castanedo.xml.crypto.dsig.CanonicalizationMethodClase; import castanedo.xml.crypto.dsig.DigestMethodClase; import castanedo.xml.crypto.dsig.XMLSignatureFactory; import castanedo.xml.crypto.dsig.keyinfo.KeyValue; import castanedo.xml.crypto.dsig.keyinfo.KeyValueClase; import castanedo.xml.crypto.dsig.keyinfo.KeyInfo; import castanedo.xml.crypto.dsig.keyinfo.KeyInfoClase; import castanedo.xml.crypto.dsig.XMLSignatureClase.SignatureValueClase; import java.util.ArrayList; import java.io.InputStream; import java.io.FileInputStream; import java.io.OutputStream; import java.io.FileOutputStream; import java.io.FileNotFoundException; import castanedo.xml.crypto.dsig.stax.GeneradorSalida; import castanedo.xml.crypto.dsig.stax.DatosFirma;

/** Contiene métodos para la generación del elemento Signature * y todos sus nodos hijos.*/

(4)

public FirmaXML() {

}

/** Crea el elemento SignedInfo */

public SignedInfoClase creaSignedInfo(String formato, String entrada,String id, String salida) {

String tipo = formato;

String docentrada = entrada; String idFirmado = "";

if (!id.equals(""))

idFirmado = "#" + id; String docsalida = salida;

// Se obtiene una instancia de la factoria de firma

XMLSignatureFactory factoria =

XMLSignatureFactory.getInstance();

// Instancia de metodo de resumen.

DigestMethodClase metres = (DigestMethodClase) factoria .newDigestMethod(DigestMethod.SHA1);

// Instancia de metodo de canonización.

CanonicalizationMethodClase canmet =

(CanonicalizationMethodClase) factoria. newCanonicalizationMethod

(CanonicalizationMethod.CANO_STAX);

// Flujo de lectura del archivo de entrada

InputStream in = null; OutputStream os = null; SignedInfoClase ifir = null; try { in = new FileInputStream(docentrada); if (!tipo.equals(Firma.ENVELOPING)) os = new FileOutputStream(docsalida); TransformClase transfcano = factoria.newTransform(Transform.CANO_STAX); ArrayList listatransforms = new ArrayList();

listatransforms.add(transfcano); if (tipo.equals(Firma.ENVELOPED)) { TransformClase transf = factoria.newTransform(Transform.ENVELOPED); listatransforms.add(transf); }

// Instancia de la referencia al documento.Crea la referencia // indicando que el tipo de firma

// es enveloping para obtener el id de los datos

ReferenceClase ref = (ReferenceClase) factoria.newReference(idFirmado,

(5)

// Instancia del método de firma.

SignatureMethodClase metfir = (SignatureMethodClase) factoria .newSignatureMethod(SignatureMethod.AES_SHA1);

// SignedInfoClase que encapsula el método de firma y la // referencia al documento

ifir = (SignedInfoClase) factoria.newSignedInfo(

(CanonicalizationMethod) canmet, (SignatureMethod) metfir,(Reference) ref);

} catch (FileNotFoundException e) {

System.err.print("No se encuentra el fichero especificado");

}

return ifir; }

/** Crea un contexto XML de firma */

public XMLSignContextClase crearContexto(byte[] clave) {

byte[] clavebyte = clave;

// Se crea el contexto de firma.

XMLSignContextClase contxt = new XMLSignContextClase();

KeyValueClase kp = new KeyValueClase(clavebyte);

// se introduce la clave en el contexto

contxt.put((KeyValue) kp);

return contxt; }

/** Crea el elemento Signature, firmando el documento en un

* determinado contexto. */

public DatosFirma crearFirma(SignedInfoClase sic,

XMLSignContextClase xmlscc, ArrayList listaparamclave, String formato) {

SignedInfoClase ifir = sic;

ArrayList listakey = listaparamclave;

KeyInfoClase ikey = new KeyInfoClase(listakey); XMLSignContextClase contxt = xmlscc;

String tipo = formato;

// Se obtiene una instancia de la factoria de firma

XMLSignatureFactory factoria =

XMLSignatureFactory.getInstance();

// Se instancia el objeto que genera la firma, pasándole inf. // de clave y de firma

XMLSignatureClase firmadocxml = (XMLSignatureClase) factoria

(6)

.newXMLSignature((KeyInfo) ikey, (SignedInfo) ifir);

// Se firma el documento con éste contexto

firmadocxml.sign((XMLSignContext) contxt, tipo);

// Se crea el elemento con los datos de la firma

DatosFirma dafisalida = new DatosFirma(firmadocxml. getSignedInfo(), firmadocxml.SignatureValue.getValue()); return dafisalida; } }

13.2 Subsistema de validación

El subsistema de validación presenta la clase Validar cuyo código es el siguiente.

Validar.java

/*

* Validar.java *

* Autor: Miguel Castanedo Doña */ import castanedo.xml.crypto.dsig.XMLValidateContext; import castanedo.xml.crypto.dsig.XMLValidateContextClase; import castanedo.xml.crypto.dsig.XMLSignatureFactory; import castanedo.xml.crypto.dsig.SignedInfo; import castanedo.xml.crypto.dsig.XMLSignatureClase; import castanedo.xml.crypto.dsig.keyinfo.KeyValue; import castanedo.xml.crypto.dsig.keyinfo.KeyValueClase; import castanedo.xml.crypto.dsig.keyinfo.KeyInfo; import castanedo.xml.crypto.dsig.keyinfo.KeyInfoClase; import castanedo.xml.crypto.dsig.XMLSignatureClase.SignatureValueClase; import java.util.ArrayList; import java.io.InputStream; import java.io.FileInputStream; import castanedo.xml.crypto.dsig.stax.LectorFirma; import castanedo.xml.crypto.dsig.stax.DatosFirma;

/** Valida documentos firmados en cualquier formato **/ public class Validar {

/**Método principal. Comprueba que el parámetro de entrada,

* documento a validar sea correcto y verifica la validez de la

* firma del documento.*/

public static void main(String[] args) {

long inicial = System.currentTimeMillis();

String docentrada = args[0]; // Parámetro: Documento a // validar.

(7)

// correspondientes a la firma

LectorFirma lf = new LectorFirma(docentrada); DatosFirma daf = lf.leer();

// Si se ha capturado una firma correcta

if (daf != null) {

// Instancia del contexto de validación

XMLValidateContextClase contxt = new

XMLValidateContextClase();

// Se valida el resumen

if (daf.SignedInfo.getReference().validate( (XMLValidateContext) contxt)) {

// Información de firma. Se crea sin parámetros // pues no son necesarios.

ArrayList listakey = new ArrayList(); listakey.add("CLAVE SIN PARAMETROS");

KeyInfoClase ikey = new KeyInfoClase(listakey);

// Se crea una instancia de la factoria de firma

XMLSignatureFactory factoria = XMLSignatureFactory .getInstance();

// Se instancia el objeto que genera la firma, // pasándole inf. de clave y de firma.

XMLSignatureClase firmadocxml =

(XMLSignatureClase) factoria. newXMLSignature((KeyInfo) ikey, (SignedInfo) daf.getSignedInfo(), daf.getSignatureValue());

// Se toma una clave

byte[] clavebyte = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12, 13, 14, 15 };

KeyValueClase kp = new KeyValueClase(clavebyte);

// se introduce la clave en el contexto

contxt.put((KeyValue) kp);

// Se valida la firma con éste contexto

if (firmadocxml.validate((XMLValidateContext) contxt))

System.out.println("La firma es válida"); else

System.out.println("La firma no es válida");

} else

System.out.println("La referencia no es válida"); }

long fin = System.currentTimeMillis(); long total = fin - inicial;

System.out.println("Tiempo empleado en la validación:" + String.valueOf(total) + " ms");

(8)

}

}

13.3 API de firma digital

Paquete castanedo.xml.crypto AlgorithmMethod.java package castanedo.xml.crypto; /* * AlgorithmMethod.java *

* Autor: Miguel Castanedo Doña */

/********************************************************************** *****

* Representación abstracta de un algoritmo definido en las

* especificaciones de seguridad XML. Las subclases representan tipos

* específicos de algoritmos de seguridad XML así como tipos Transform.

*********************************************************************** ***/

public interface AlgorithmMethod {

/** Devuelve el nombre del algoritmo **/

public String getAlgorithm();

} KeySelector.java package castanedo.xml.crypto; /* * KeySelector.java *

* Autor: Miguel Castanedo Doña */

/** Clase abstracta para indicar el ** propósito del cifrado**/

public abstract class KeySelector { protected KeySelector() {

(9)

/**Propósito con el que

* se usa la clave **/

public static class Purpose { private Purpose() {

};

/**Desencriptar **/

public static final int DECRYPT = 1;

/**Encriptar **/

public static final int ENCRYPT = 2;

/**Firmar **/

public static final int SIGN = 3;

/**Verificar **/

public static final int VERIFY = 4;

public String toString() { if (this.toString() == "1") return "decrypt";

else if (this.toString() == "2") return "encrypt";

else if (this.toString() == "3") return "sign";

else if (this.toString() == "4") return "verify";

else

return "Propósito incorrecto"; } } } URIReference.java package castanedo.xml.crypto; /* * URIReference.java *

* Autor: Miguel Castanedo Doña */

/**

* Identifica un objeto de datos via URI-Reference, como se

* especifica en

* RFC 2396.

*/

public interface URIReference {

(10)

public String getURI(); } URIReferenceClase.java package castanedo.xml.crypto; /* * URIReferenceClase.java *

* Autor: Miguel Castanedo Doña */

/** implementación de la interfaz URIReference.

** Recibe como parámetro un String URI al instanciarse. ** con el método getURI() se puede recuperar este String **/ public class URIReferenceClase implements URIReference {

String uri;

public URIReferenceClase(String uri) { this.uri = uri;

}

/**Devuelve el URI**/

public String getURI(){ return this.uri; } } XMLCryptoContext.java package castanedo.xml.crypto; /* * XMLCryptoContext.java *

* Autor: Miguel Castanedo Doña */

import castanedo.xml.crypto.dsig.keyinfo.KeyValue;

/***************************************************************************

* Contiene información de contexto común para operaciones

* criptográficas

* XML.

*

* Ésta interfaz contiene métodos para establecer y recuperar

* propiedades

* que afectan al proceso de firma XML o a las estructuras XML

(11)

* Las instancias XMLCryptoContext pueden contener información y estado

* específico de la estructura criptográfica XML. Los resultados son

* impredecibles si un XMLCryptoContext se usa con múltiples estructuras

* (por ejemplo no se debe usar la misma instancia de XMLValidateContext

* para validar dos objetos XMLSignature diferentes).

**************************************************************************/ public interface XMLCryptoContext {

/**Devuelve el URI base del contexto **/

public String getBaseURI();

/**Establece el URI base del contexto **/

public void setBaseURI(String baseURI);

/**Devuelve el seleccionador de claves del contexto **/

public KeySelector getKeySelector();

/**Establece el seleccionador de claves del contexto **/

public void setKeySelector(KeySelector ks);

/** Devuelve un objeto KeyValue con el valor de la clave **/

public KeyValue get();

/**Establece el valor de la clave **/

public void put(KeyValue value);

} Paquete castanedo.xml.crypto.dsig

CanonicalizationMethod.java

package castanedo.xml.crypto.dsig; /* * CanonicalizationMethod.java *

* Autor: Miguel Castanedo Doña */

import castanedo.xml.crypto.AlgorithmMethod;

import java.util.ArrayList;

/** interfaz que define el método de canonización **/

public interface CanonicalizationMethod extends AlgorithmMethod {

public static final String EXCLUSIVE =

(12)

public static final String EXCLUSIVE_WITH_COMMENTS =

"http://www.w3.org/2001/10/xml-exc-c14n#WithComments";

public static final String INCLUSIVE =

"http://www.w3.org/TR/2001/REC-xml-c14n-20010315";

public static final String INCLUSIVE_WITH_COMMENTS =

"http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments";

public static final String CANO_STAX =

"http://www.w3.org/TR/2001/Cano_Stax"; } CanonicalizationMethodClase.java package castanedo.xml.crypto.dsig; /* * CanonicalizationMethodClase.java *

* Autor: Miguel Castanedo Doña */

/** Clase que establece el nombre del método de canonización a utilizar.

* Implementa la interfaz CanonicalizationMethod*/ public class CanonicalizationMethodClase implements

CanonicalizationMethod { String Algorithm;

/** Constructor de la clase. Recibe como parámetro

* el nombre del algoritmo de canonización**/

public CanonicalizationMethodClase(String algoritmo) { this.Algorithm = algoritmo;

}

/**Obtiene el nombre del algoritmo de canonización**/

public String getAlgorithm() { return this.Algorithm; }

}

(13)

package castanedo.xml.crypto.dsig;

/*

* DatosNombre.java *

* Autor: Miguel Castanedo Doña */

import java.util.ArrayList;

/**

* Clase que encapsula el nombre local de un nodo * y su espacio de nombres.

*/

public class DatosNombre {

public String qname;

ArrayList espacionombre;

/**

* Constructor de la clase

* @param qname: Nombre local del nodo

* @param espacionombre: Espacio de nombres asociado al nodo

*/

public DatosNombre(String qname, ArrayList espacionombre ) {

this.qname = qname;

this.espacionombre = espacionombre; }

/**

* Obtiene el nombre del nodo

*/

public String getQname() {

return qname; }

/**

* Obtiene el espacio de nombres al que pertenece el nodo.

* */

public ArrayList getNamespace() {

return espacionombre; }

(14)

DigestMethod.java

package castanedo.xml.crypto.dsig;

/*

* DigestMethod.java *

* Autor: Miguel Castanedo Doña */

import castanedo.xml.crypto.AlgorithmMethod;

import java.util.ArrayList;

/** interfaz que establece el método de resumen */ public interface DigestMethod extends AlgorithmMethod {

/** Se define MD5 como método de resumen */

public static final String MD5 =

"http://www.w3.org/2000/09/xmldsig#md5";

/** Se define SHA1 como método de resumen */

public static final String SHA1 =

"http://www.w3.org/2000/09/xmldsig#sha1"; } DigestMethodClase.java package castanedo.xml.crypto.dsig; /* * DigestMethodClase.java *

* Autor: Miguel Castanedo Doña */

/** Clase que representa el nombre de un algoritmo de resumen. * Implementa la interfaz DigestMethod*/

public class DigestMethodClase implements DigestMethod { String Algorithm;

/**

* Constructor de la clase

* @param algoritmo: Nombre del algoritmo

* de resumen.

*/

public DigestMethodClase(String algoritmo) { this.Algorithm = algoritmo;

}

/**Devuelve el Nombre del algoritmo de resumen**/

public String getAlgorithm() { return this.Algorithm; }

(15)

} Firma.java package castanedo.xml.crypto.dsig; /* * Firma.java *

* Autor: Miguel Castanedo Doña */

/**Interfaz que define constantes utilizadas * en el proceso de firma o validación**/ public interface Firma {

public static final String ENVELOPED = "enveloped";

public static final String ENVELOPING = "enveloping";

public static final String DETACHED = "detached";

public static final String SIGNATURE = "Signature";

public static final String SIGNED_INFO = "SignedInfo";

public static final String CANONICALIZATION_METHOD = "CanonicalizationMethod";

public static final String ALGORITHM = "Algorithm";

public static final String SIGNATURE_METHOD = "SignatureMethod";

public static final String REFERENCE = "Reference";

public static final String URI = "URI";

public static final String TRANSFORMS = "Transforms";

public static final String TRANSFORM = "Transform";

public static final String DIGEST_METHOD = "DigestMethod";

public static final String DIGEST_VALUE = "DigestValue";

public static final String SIGNATURE_VALUE = "SignatureValue";

public static final String OBJECT = "Object";

public static final String ID = "ID";

public static final String ROOT = "root";

(16)

public static final String TAB = " "; } MD5Digest.java package castanedo.xml.crypto.dsig; /** * Implementación del * algoritmo MD5 */

public class MD5Digest

{

private static final int DIGEST_LENGTH = 16;

private int H1, H2, H3, H4; // IV's

private int[] X = new int[16];

private int xOff;

private byte[] xBuf = new byte[4];

private int xBufOff = 0;

private long byteCount;

public void update(byte in) { xBuf[xBufOff++] = in; if (xBufOff == xBuf.length) { processWord(xBuf, 0); xBufOff = 0; } byteCount++; }

public void update(byte[] in, int inOff, int len) { //

// rellena la actual palabra.

//

while ((xBufOff != 0) && (len > 0)) { update(in[inOff]);

inOff++; len--; }

//

// procesa palabras completas.

(17)

while (len > xBuf.length) { processWord(in, inOff); inOff += xBuf.length; len -= xBuf.length; byteCount += xBuf.length; } // // carga en el resto. // while (len > 0) { update(in[inOff]); inOff++; len--; } }

public void finish() {

long bitLength = (byteCount << 3);

//

// añade los bytes de paridad.

// update((byte) 128); while (xBufOff != 0) { update((byte) 0); } processLength(bitLength); processBlock(); } /** * constructor estándar */ public MD5Digest() { reset(); }

public String getAlgorithmName() { return "MD5";

}

public int getDigestSize() { return DIGEST_LENGTH; }

protected void processWord(byte[] in, int inOff) {

X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8) | ((in[inOff + 2] & 0xff) << 16)

| ((in[inOff + 3] & 0xff) << 24);

if (xOff == 16) { processBlock();

(18)

} }

protected void processLength(long bitLength) { if (xOff > 14) {

processBlock(); }

X[14] = (int) (bitLength & 0xffffffff); X[15] = (int) (bitLength >>> 32);

}

private void unpackWord(int word, byte[] out, int outOff) { out[outOff] = (byte) word;

out[outOff + 1] = (byte) (word >>> 8); out[outOff + 2] = (byte) (word >>> 16); out[outOff + 3] = (byte) (word >>> 24); }

public int doFinal(byte[] out, int outOff) { finish();

unpackWord(H1, out, outOff); unpackWord(H2, out, outOff + 4); unpackWord(H3, out, outOff + 8); unpackWord(H4, out, outOff + 12);

reset();

return DIGEST_LENGTH; }

/**

* resetea las variables chaining a los valores IV.

*/

public void reset() { byteCount = 0;

xBufOff = 0;

for (int i = 0; i < xBuf.length; i++) { xBuf[i] = 0; } H1 = 0x67452301; H2 = 0xefcdab89; H3 = 0x98badcfe; H4 = 0x10325476; xOff = 0;

for (int i = 0; i != X.length; i++) { X[i] = 0;

} }

//

// round 1 rotaciones izqda

(19)

private static final int S11 = 7;

private static final int S12 = 12;

private static final int S13 = 17;

private static final int S14 = 22;

//

// round 2 rotaciones izqda

//

private static final int S21 = 5;

private static final int S22 = 9;

private static final int S23 = 14;

private static final int S24 = 20;

//

// round 3 rotaciones izqda

//

private static final int S31 = 4;

private static final int S32 = 11;

private static final int S33 = 16;

private static final int S34 = 23;

//

// round 4 rotaciones izqda

//

private static final int S41 = 6;

private static final int S42 = 10;

private static final int S43 = 15;

private static final int S44 = 21;

/*

* rota x posiciones los n bits. */

private int rotateLeft(int x, int n) { return (x << n) | (x >>> (32 - n)); }

/*

* F, G, H e I son las funciones básicas MD5. */

private int F(int u, int v, int w) { return (u & v) | (~u & w);

}

private int G(int u, int v, int w) { return (u & w) | (v & ~w);

(20)

private int H(int u, int v, int w) { return u ^ v ^ w;

}

private int K(int u, int v, int w) { return v ^ (u | ~w);

}

protected void processBlock() { int a = H1;

int b = H2; int c = H3; int d = H4;

//

// Round 1 - F ciclos, 16 veces.

//

a = rotateLeft((a + F(b, c, d) + X[0] + 0xd76aa478), S11) + b; d = rotateLeft((d + F(a, b, c) + X[1] + 0xe8c7b756), S12) + a; c = rotateLeft((c + F(d, a, b) + X[2] + 0x242070db), S13) + d; b = rotateLeft((b + F(c, d, a) + X[3] + 0xc1bdceee), S14) + c; a = rotateLeft((a + F(b, c, d) + X[4] + 0xf57c0faf), S11) + b; d = rotateLeft((d + F(a, b, c) + X[5] + 0x4787c62a), S12) + a; c = rotateLeft((c + F(d, a, b) + X[6] + 0xa8304613), S13) + d; b = rotateLeft((b + F(c, d, a) + X[7] + 0xfd469501), S14) + c; a = rotateLeft((a + F(b, c, d) + X[8] + 0x698098d8), S11) + b; d = rotateLeft((d + F(a, b, c) + X[9] + 0x8b44f7af), S12) + a; c = rotateLeft((c + F(d, a, b) + X[10] + 0xffff5bb1), S13) + d; b = rotateLeft((b + F(c, d, a) + X[11] + 0x895cd7be), S14) + c; a = rotateLeft((a + F(b, c, d) + X[12] + 0x6b901122), S11) + b; d = rotateLeft((d + F(a, b, c) + X[13] + 0xfd987193), S12) + a; c = rotateLeft((c + F(d, a, b) + X[14] + 0xa679438e), S13) + d; b = rotateLeft((b + F(c, d, a) + X[15] + 0x49b40821), S14) + c; //

// Round 2 - G ciclos, 16 veces.

// a = rotateLeft((a + G(b, c, d) + X[1] + 0xf61e2562), S21) + b; d = rotateLeft((d + G(a, b, c) + X[6] + 0xc040b340), S22) + a; c = rotateLeft((c + G(d, a, b) + X[11] + 0x265e5a51), S23) + d; b = rotateLeft((b + G(c, d, a) + X[0] + 0xe9b6c7aa), S24) + c; a = rotateLeft((a + G(b, c, d) + X[5] + 0xd62f105d), S21) + b; d = rotateLeft((d + G(a, b, c) + X[10] + 0x02441453), S22) + a; c = rotateLeft((c + G(d, a, b) + X[15] + 0xd8a1e681), S23) + d; b = rotateLeft((b + G(c, d, a) + X[4] + 0xe7d3fbc8), S24) + c; a = rotateLeft((a + G(b, c, d) + X[9] + 0x21e1cde6), S21) + b; d = rotateLeft((d + G(a, b, c) + X[14] + 0xc33707d6), S22) + a; c = rotateLeft((c + G(d, a, b) + X[3] + 0xf4d50d87), S23) + d; b = rotateLeft((b + G(c, d, a) + X[8] + 0x455a14ed), S24) + c; a = rotateLeft((a + G(b, c, d) + X[13] + 0xa9e3e905), S21) + b; d = rotateLeft((d + G(a, b, c) + X[2] + 0xfcefa3f8), S22) + a; c = rotateLeft((c + G(d, a, b) + X[7] + 0x676f02d9), S23) + d; b = rotateLeft((b + G(c, d, a) + X[12] + 0x8d2a4c8a), S24) + c;

//

// Round 3 - H ciclos, 16 veces.

(21)

a = rotateLeft((a + H(b, c, d) + X[5] + 0xfffa3942), S31) + b; d = rotateLeft((d + H(a, b, c) + X[8] + 0x8771f681), S32) + a; c = rotateLeft((c + H(d, a, b) + X[11] + 0x6d9d6122), S33) + d; b = rotateLeft((b + H(c, d, a) + X[14] + 0xfde5380c), S34) + c; a = rotateLeft((a + H(b, c, d) + X[1] + 0xa4beea44), S31) + b; d = rotateLeft((d + H(a, b, c) + X[4] + 0x4bdecfa9), S32) + a; c = rotateLeft((c + H(d, a, b) + X[7] + 0xf6bb4b60), S33) + d; b = rotateLeft((b + H(c, d, a) + X[10] + 0xbebfbc70), S34) + c; a = rotateLeft((a + H(b, c, d) + X[13] + 0x289b7ec6), S31) + b; d = rotateLeft((d + H(a, b, c) + X[0] + 0xeaa127fa), S32) + a; c = rotateLeft((c + H(d, a, b) + X[3] + 0xd4ef3085), S33) + d; b = rotateLeft((b + H(c, d, a) + X[6] + 0x04881d05), S34) + c; a = rotateLeft((a + H(b, c, d) + X[9] + 0xd9d4d039), S31) + b; d = rotateLeft((d + H(a, b, c) + X[12] + 0xe6db99e5), S32) + a; c = rotateLeft((c + H(d, a, b) + X[15] + 0x1fa27cf8), S33) + d; b = rotateLeft((b + H(c, d, a) + X[2] + 0xc4ac5665), S34) + c;

//

// Round 4 - K ciclos, 16 veces.

//

a = rotateLeft((a + K(b, c, d) + X[0] + 0xf4292244), S41) + b; d = rotateLeft((d + K(a, b, c) + X[7] + 0x432aff97), S42) + a; c = rotateLeft((c + K(d, a, b) + X[14] + 0xab9423a7), S43) + d; b = rotateLeft((b + K(c, d, a) + X[5] + 0xfc93a039), S44) + c; a = rotateLeft((a + K(b, c, d) + X[12] + 0x655b59c3), S41) + b; d = rotateLeft((d + K(a, b, c) + X[3] + 0x8f0ccc92), S42) + a; c = rotateLeft((c + K(d, a, b) + X[10] + 0xffeff47d), S43) + d; b = rotateLeft((b + K(c, d, a) + X[1] + 0x85845dd1), S44) + c; a = rotateLeft((a + K(b, c, d) + X[8] + 0x6fa87e4f), S41) + b; d = rotateLeft((d + K(a, b, c) + X[15] + 0xfe2ce6e0), S42) + a; c = rotateLeft((c + K(d, a, b) + X[6] + 0xa3014314), S43) + d; b = rotateLeft((b + K(c, d, a) + X[13] + 0x4e0811a1), S44) + c; a = rotateLeft((a + K(b, c, d) + X[4] + 0xf7537e82), S41) + b; d = rotateLeft((d + K(a, b, c) + X[11] + 0xbd3af235), S42) + a; c = rotateLeft((c + K(d, a, b) + X[2] + 0x2ad7d2bb), S43) + d; b = rotateLeft((b + K(c, d, a) + X[9] + 0xeb86d391), S44) + c; H1 += a; H2 += b; H3 += c; H4 += d; //

// resetea el offset y limpia el buffer.

//

xOff = 0;

for (int i = 0; i != X.length; i++) { X[i] = 0;

} } }

(22)

Reference.java

package castanedo.xml.crypto.dsig;

/*

* Reference.java *

* Autor: Miguel Castanedo Doña */ import castanedo.xml.crypto.URIReference; import java.io.InputStream; import java.util.ArrayList; import javax.xml.stream.XMLStreamWriter; /**

* Interfaz que encapsula un objeto con el método de resumen a emplear. Permite

* calcular el resumen, y validar el resumen de un documento */

public interface Reference extends URIReference {

/**Devuelve el método de cálculo de resumen**/

public DigestMethod getDigestMethod();

/**Calcula el resumen y devuelve el flujo de salida

* en el que ha generado el documento de salida

* paralelamente **/

public XMLStreamWriter getDigestValue();

/**Devuelve la lista de transformaciones que

* se aplican al documento de entrada para

* generar la firma**/

public ArrayList getTransforms();

/**Devuelve el valor del resumen calculado**/

public byte[] getCalculatedDigestValue();

/**Valida el valor de un resumen en un determinado contexto**/

public boolean validate(XMLValidateContext validateContext);

/**Devuelve el flujo del documento de entrada**/

public InputStream getDigestInputStream(); } ReferenceClase.java package castanedo.xml.crypto.dsig; /* * Referencelase.java *

* Autor: Miguel Castanedo Doña */

import java.io.IOException;

(23)

import java.io.OutputStream; import java.io.UnsupportedEncodingException; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLInputFactory; import javax.xml.namespace.QName; import java.io.StringWriter; import java.util.ArrayList; import com.bea.xml.stream.MXParserFactory; import org.apache.commons.codec.binary.Base64; import com.wutka.dtd.DTDParser; /********************************************************************* **********

* ReferenceClase implementa Reference que extiende URIReference. * Contiene métodos para calcular el digest, leyendo el XML a partir

* de un flujo

* de entrada, aplicando las transformaciones necesarias incluida la * canonización y generando simultáneamente el documento de salida. ********************************************************************** ********/

public class ReferenceClase implements Reference {

String URI;

DigestMethodClase DigestMethod;

// Almacena el digest calculado

byte[] DigestValue = new byte[20];

// Se usa para almacenar el valor del resumen de una referencia // para validarla

byte[] digestsinvalidar;

// Flujo de entrada al archivo xml a resumir

InputStream flujoin;

// Flujo de salida

OutputStream flujout;

// Formato de firma

String tipo;

// Transformaciones a tener en cuenta para calcular el resumen

ArrayList transforms;

/** Constructor usado para crear una referencia

* incluyendo el valor del digest.

(24)

public ReferenceClase(String uri, DigestMethod dm, InputStream flujoin,ArrayList transforms, byte[] digestsinvalidar) {

this.URI = uri;

this.DigestMethod = (DigestMethodClase) dm; this.flujoin = flujoin;

this.transforms = transforms;

this.digestsinvalidar = digestsinvalidar; this.tipo = "";

this.flujout = null;

}

/** Constructor usado para crear una referencia

* a la que aún no se ha calculado el digest.**/

public ReferenceClase(String uri, DigestMethod dm, InputStream flujoin,

ArrayList transforms, OutputStream os, String formato) {

this.URI = uri;

this.DigestMethod = (DigestMethodClase) dm; this.flujoin = flujoin;

this.transforms = transforms; this.tipo = formato;

this.flujout = os;

}

/** Devuelve el identificador del método de resumen utilizado**/

public DigestMethod getDigestMethod() {

return this.DigestMethod; }

/** Devuelve el valor del resumen calculado.**/

public byte[] getCalculatedDigestValue() { return DigestValue;

}

/** Calcula el resumen, canonizando la entrada y generando el

* documento de

* salida con los datos que se firman antes de incluir la firma.

* Devuelve el flujo XML mediante el que se está generando la

* salida de forma que pueda añadirse la firma antes de cerrar

* dicho flujo**/

public XMLStreamWriter getDigestValue() {

long inicial = System.currentTimeMillis();

/** Declaración de variables */

String eltoreferenciado = ""; // Almacena el nombre del //elemento que se resume.

boolean finencontrado = false; // Flag que indica cuando //finalizan los

// datos a resumir

boolean encontrado = false; // Flag que indica cuando // comienzan los

(25)

// datos a resumir

boolean parar = false;

String primerElemento = ""; // Guarda el nombre local del //primer elemento para

// incluir la firma antes que finalice si es ENVELOPED

// String donde se almacena cada evento

String eventcadena = new String(); // Algoritmo de resumen

// MD5Digest resumen = new MD5Digest();

SHA1Digest resumen = new SHA1Digest();

// Byte array donde se almacenará el resumen calculado

byte[] byteresumen = new byte[20];

// Crea flujo xml de salida si no es formato Enveloping

XMLStreamWriter xswSalida = null;

//Almacena el espacio de nombres correspondiente a cada elto.

ArrayList nombres = new ArrayList();

// Establece el parseador

System.setProperty("javax.xml.stream.XMLInputFactory", "com.bea.xml.stream.MXParserFactory");

try {

// Crea la factoría de entrada xml e instancia el flujo // xml de entrada XMLStreamReader xsr = XMLInputFactory.newInstance() .createXMLStreamReader(flujoin); if (!tipo.equals(Firma.ENVELOPING)) xswSalida = XMLOutputFactory.newInstance() .createXMLStreamWriter(flujout);

// Bandera que indica si se ha escrito el último elemento

boolean escrito = false;

// escribe el elemento que engloba a la firma y datos // firmados para detached

if (tipo.equals(Firma.DETACHED))

xswSalida.writeStartElement(Firma.ROOT);

// Bucle de lectura del documento xml

while (xsr.hasNext()&&!parar) {

// evita evaluar si no se está en el elemento // referenciado salvo si es ENVELOPED

if (tipo.equals(Firma.ENVELOPED) || encontrado || (xsr.getEventType() == XMLStreamReader.START_ELEMENT) || (xsr.getEventType() == XMLStreamReader.END_ELEMENT)) {

(26)

XMLStreamWriter xsw =

XMLOutputFactory.newInstance() .createXMLStreamWriter(sw);

switch (xsr.getEventType()) // Distingue los //distintos tipos // de eventos { // ATRIBUTO case XMLStreamReader.ATTRIBUTE: escrito = true; xsw.writeAttribute(xsr.getPrefix(), xsr .getNamespaceURI(), xsr.getLocalName(), xsr .getText());

if (!tipo.equals(Firma.ENVELOPING) && !parar) xswSalida.writeAttribute(xsr.getPrefix(), xsr.getNamespaceURI(),

xsr.getLocalName(), toUTF8(xsr .getText()));

break;

// DATOS SIN FORMATO

case XMLStreamReader.CDATA:

escrito = true;

xsw.writeCData(xsr.getText());

if (!tipo.equals(Firma.ENVELOPING) && !parar) xswSalida .writeCData(toUTF8(xsr.getText())); break; // CARACTERES case XMLStreamReader.CHARACTERS: escrito = true; xsw.writeCharacters(xsr.getText()); if (!tipo.equals(Firma.ENVELOPING) && !parar){ xswSalida. writeCharacters(toUTF8(xsr.getText())); } break; // COMENTARIOS case XMLStreamReader.COMMENT: escrito = true; xsw.writeComment(xsr.getText());

(27)

xswSalida. writeComment(toUTF8(xsr.getText())); break; // DTD case XMLStreamReader.DTD: escrito = false;

if (!tipo.equals(Firma.ENVELOPING) && !parar) // xswSalida.writeDTD(xsr.getText()); break; // FIN DE DOCUMENTO case XMLStreamReader.END_DOCUMENT: escrito = false; // xsw.writeEndDocument(); break; // FIN DE ELEMENTO case XMLStreamReader.END_ELEMENT: if (tipo.equals(Firma.ENVELOPED) && primerElemento. equals(xsr.getLocalName())) parar = true;

if (!tipo.equals(Firma.ENVELOPING) && !parar && (tipo.equals(Firma.ENVELOPED) || encontrado))

xswSalida.writeEndElement();

escrito = true;

xsw.writeCharacters(xsr.getLocalName());

//Elimina de la lista el espacio de nombres //de elemento finalizado

nombres.remove(nombres.size()-1);

// Identifica si acaba el elemento // referenciado por el

// uri, activando el flag correspondiente

if (eltoreferenciado. equals(xsr.getLocalName())) { finencontrado = true; } break; // DECLARACIÓN DE ENTIDAD case XMLStreamReader.ENTITY_DECLARATION: escrito = false;

(28)

break;

// REFERENCIA A ENTIDAD

case XMLStreamReader.ENTITY_REFERENCE: escrito = true;

xsw.writeEntityRef(xsr.getText());

if (!tipo.equals(Firma.ENVELOPING) && !parar) xswSalida.writeEntityRef(xsr.getText()); break; // ESPACIO DE NOMBRES case XMLStreamReader.NAMESPACE: escrito = true; xsw.writeNamespace(xsr.getPrefix(), xsr .getNamespaceURI());

if (!tipo.equals(Firma.ENVELOPING) && !parar) xswSalida.writeNamespace(xsr.getPrefix(), xsr.getNamespaceURI()); break; // DECLARACIÓN DE NOTACIÓN case XMLStreamReader.NOTATION_DECLARATION: escrito = false; break; // INSTRUCCIÓN case XMLStreamReader.PROCESSING_INSTRUCTION: escrito = true; xsw.writeProcessingInstruction(xsr .getPITarget(), xsr .getPIData());

if (!tipo.equals(Firma.ENVELOPING) && !parar) xswSalida.writeProcessingInstruction(xsr .getPITarget(), xsr.getPIData()); break; // ESPACIO EN BLANCO case XMLStreamReader.SPACE: if (escrito) { xsw.writeCharacters(Firma.FIN_LINEA); escrito = false; }

if (!tipo.equals(Firma.ENVELOPING) && !parar && escrito)

(29)

xswSalida .writeCharacters(Firma.FIN_LINEA); break; // COMIENZO DE DOCUMENTO case XMLStreamReader.START_DOCUMENT: escrito = false; break; // COMIENZO DE ELEMENTO case XMLStreamReader.START_ELEMENT: if (primerElemento.equals("")) // almacena el //valor del // primer //elto. USADO // para //ENVELOPED primerElemento = xsr.getLocalName(); xsw.writeStartElement(xsr .getPrefix() == null ? "" : xsr.getPrefix(), xsr.getLocalName(), xsr .getNamespaceURI()); escrito = true; int at = xsr.getAttributeCount(); if (!tipo.equals(Firma.ENVELOPED)) { for (int j = 0; j < at; j++) {

if (xsr.getAttributeLocalName(j) .toUpperCase()

.equals(Firma.ID) && this.URI.equals("#"

+ xsr.getAttributeValue(j))) { encontrado = true; eltoreferenciado = xsr.getLocalName(); } } }

if (!tipo.equals(Firma.ENVELOPING) && !parar && (tipo.equals(Firma.ENVELOPED) || encontrado)) { xswSalida.writeStartElement( xsr.getPrefix() == null ? "" : xsr.getPrefix(), xsr.getLocalName(), xsr.getNamespaceURI()); escribeNamespaces(nombres,xsr,xswSalida); //Elimina de la lista el espacio de

(30)

//nombres del elemento

//puesto que se va a volver a incocar el //método

//para calcular el resumen

nombres.remove(nombres.size()-1); }

escribeNamespaces(nombres,xsr,xsw);

int attrs = xsr.getAttributeCount(); if (attrs > 0) {

ArrayList atributos = new ArrayList(); ArrayList atributosuri = new ArrayList(); ArrayList listaindex = new ArrayList();

for (int j = 0; j < attrs; j++) {

String [] elemento = new String[2]; elemento[0] = String.valueOf(j); if(xsr.getAttributeNamespace(j)=="") { atributos.add(xsr .getAttributeLocalName(j)); elemento[1] =xsr .getAttributeLocalName(j); }else { atributosuri.add(xsr .getAttributeNamespace(j)+"="+ xsr. getAttributeLocalName(j)); elemento[1] =xsr .getAttributeNamespace(j)+"="+ xsr. getAttributeLocalName(j); } listaindex.add(elemento); if (xsr.getAttributeLocalName(j) .toUpperCase() .equals(Firma.ID) && this.URI.equals("#"

+ xsr.getAttributeValue(j))) { encontrado = true; eltoreferenciado = xsr.getLocalName(); } } if(atributos.size()>0){ String [] attr = new

String[atributos.size()];

for (int i = 0; i <atributos.size() ; i++)

(31)

attr[i] = (String)atributos.get(i); }

quickSort(attr, attr.length);

for (int i = 0; i <attr.length ; i++) { int indexencontrado = -1; String [] eltosalida; for (int j = 0; j <listaindex.size() ; j++) { eltosalida=(String[]) listaindex.get(j); if(attr[i]. equals(eltosalida[1])) { indexencontrado = j; xsw.writeAttribute(xsr .getAttributePrefix(Integer .parseInt(eltosalida[0]))==null ? "" : xsr .getAttributePrefix(Integer .parseInt(eltosalida[0])), xsr.getAttributeNamespace(Integer .parseInt(eltosalida[0])), xsr.getAttributeLocalName(Integer .parseInt(eltosalida[0])), normalizar_espacios(xsr. getAttributeValue(Integer .parseInt(eltosalida[0])))); if

(!tipo.equals(Firma.ENVELOPING) && !parar && (tipo.equals(Firma.ENVELOPED) || encontrado)) { xswSalida.writeAttribute(xsr.getAttributePrefix(Integer.parseInt(eltos alida[0]))==null ? "" : xsr.getAttributePrefix(Integer.parseInt(eltosalida[0])), xsr.getAttributeNamespace(Integer.parseInt(eltosalida[0])), xsr.getAttributeLocalName(Integer.parseInt(eltosalida[0])),normalizar_ espacios(xsr. getAttributeValue(Integer.parseInt(eltosalida[0])))); } } } if(indexencontrado!=-1)

(32)

listaindex.remove(indexencontrado);

} }

if(atributosuri.size()>0){ String [] attruri = new

String[atributosuri.size()];

for (int i = 0; i <atributosuri.size() ; i++) { attruri[i] = (String)atributosuri.get(i); } quickSort(attruri, attruri.length);

for (int i = 0; i <attruri.length ; i++)

{

int indexencontradouri = -1; String [] eltosalidauri;

for (int j = 0; j <listaindex.size() ; j++) { eltosalidauri = (String[])listaindex.get(j); if(eltosalidauri[1].equals(attruri[i])) { indexencontradouri = j; xsw.writeAttribute(xsr.getAttributePrefix(Integer.parseInt(eltosalidau ri[0]))==null ? "" : xsr.getAttributePrefix(Integer.parseInt(eltosalidauri[0])), xsr.getAttributeNamespace(Integer.parseInt(eltosalidauri[0])), xsr.getAttributeLocalName(Integer.parseInt(eltosalidauri[0])),normaliz ar_espacios(xsr. getAttributeValue(Integer.parseInt(eltosalidauri[0])))); if

(!tipo.equals(Firma.ENVELOPING) && !parar && (tipo.equals(Firma.ENVELOPED) || encontrado)) { xswSalida.writeAttribute(xsr.getAttributePrefix(Integer.parseInt(eltos alidauri[0]))==null ? "" : xsr.getAttributePrefix(Integer.parseInt(eltosalidauri[0])), xsr.getAttributeNamespace(Integer.parseInt(eltosalidauri[0])), xsr.getAttributeLocalName(Integer.parseInt(eltosalidauri[0])),normaliz ar_espacios(xsr.

(33)

getAttributeValue(Integer.parseInt(eltosalidauri[0])))); } } } if(indexencontradouri!=-1) listaindex.remove(indexencontradouri); } } } break; } if (escrito) { xsw.flush(); eventcadena = sw.toString(); if (xsr.getEventType() == XMLStreamReader.START_ELEMENT) eventcadena += ">"; else if (xsr.getEventType() == XMLStreamReader.END_ELEMENT) eventcadena = "</" + eventcadena + ">"; }

// Si el formato de firma es Enveloped, se firma todo el

// documento

if (tipo.equals(Firma.ENVELOPED)) {

if (escrito && !primerElemento.equals("")) { // ACTUALIZA EL RESUMEN resumen.update(eventcadena.getBytes( "UTF-8"), 0, eventcadena.getBytes( "UTF-8").length); //System.out.println("Resume1: "+ eventcadena); }

} else { // Si no es Enveloped sólo se añade al resumen

// el elemento referenciado por URI

if (escrito && encontrado) {

// ACTUALIZA EL RESUMEN resumen.update(eventcadena.getBytes( "UTF-8"), 0, eventcadena.getBytes( "UTF-8").length); }

(34)

}

}// fin if evita evaluar

// TOMA EL SIGUIENTE EVENTO

xsr.next(); if (finencontrado) { encontrado = false; finencontrado = false; } }

// Se cierran los flujos al finalizar la lectura del documento

xsr.close(); flujoin.close();

// CÁLCULO DEL RESUMEN FINAL

resumen.doFinal(byteresumen, 0);

// Se asigna el valor calculado a DigestValue

DigestValue = byteresumen;

long fin = System.currentTimeMillis();

System.out.println("Tiempo de cálculo del resumen: "

+String.valueOf(fin-inicial)+ " ms");

return xswSalida;

} catch (XMLStreamException e) {

System.err.print("Error de flujo XML:" +e.getMessage()); return null;

} catch (UnsupportedEncodingException e) { System.err.print("Error de codificación:"

+e.getMessage());

return null;

} catch (IOException e) {

System.err.print("Error cerrando flujo de entrada:"

+e.getMessage());

return null; }

}

/**

* Método para validar una referencia en un contexto determinado.

* Calcula de nuevo el digest a partir de un flujo de entrada y

* lo compara con el almacenado en la referencia. Devuelve true

* si la referencia es correcta y false en caso contrario*/

public boolean validate(XMLValidateContext validateContext) {

/** Declaración de variables */

String eltoreferenciado = ""; // Almacena el nombre del elemento que

(35)

boolean finencontrado = false; // Flag que indica cuando finalizan los

// datos a resumir

boolean encontrado = false; // Flag que indica cuando comienzan los

// datos a resumir

boolean signature = false; // Flag que indica cuando comienza el

// elemento Signature

boolean finsignature = false; // Flag que indica cuando termina el

// elemento Signature

// Resultado de la validación del resumen

boolean valido = true;

// String donde se almacena cada evento

String eventcadena = new String();

// Algoritmo de resumen

// MD5Digest resumen = new MD5Digest();

SHA1Digest resumen = new SHA1Digest();

// Byte array donde se almacenará el resumen calculado

byte[] byteresumen = new byte[20];

// Establece el parseador

System.setProperty("javax.xml.stream.XMLInputFactory", "com.bea.xml.stream.MXParserFactory");

boolean parar = false;

String primerElemento = ""; // Guarda el nombre local del primer

// elemento

//Almacena el espacio de nombres correspondiente a cada elto.

ArrayList nombres = new ArrayList(); try {

// Crea la factoría de entrada xml e instancia el flujo xml de

// entrada

XMLStreamReader xsr = XMLInputFactory.newInstance() .createXMLStreamReader(flujoin);

// Bandera que indica si se ha escrito el último elemento

boolean escrito = false;

// Bucle de lectura del documento xml

while (xsr.hasNext()&&!parar) {

// evita evaluar si no se está en el elemento referenciado

// salvo si es ENVELOPED

if (URI.equals("") || encontrado

|| (xsr.getEventType() == XMLStreamReader.START_ELEMENT)){

(36)

XMLStreamWriter xsw = XMLOutputFactory.newInstance() .createXMLStreamWriter(sw);

switch (xsr.getEventType()) // Distingue los distintos tipos de // eventos { // ATRIBUTO case XMLStreamReader.ATTRIBUTE: escrito = true; xsw.writeAttribute(xsr.getPrefix(), xsr.getNamespaceURI(), xsr.getLocalName(), xsr.getText()); break;

// DATOS SIN FORMATO

case XMLStreamReader.CDATA: escrito = true; xsw.writeCData(xsr.getText()); break; // CARACTERES case XMLStreamReader.CHARACTERS: escrito = true; xsw.writeCharacters(xsr.getText()); break; // COMENTARIOS case XMLStreamReader.COMMENT: escrito = true; xsw.writeComment(xsr.getText()); break; // DTD case XMLStreamReader.DTD: escrito = false; break; // FIN DE DOCUMENTO case XMLStreamReader.END_DOCUMENT: escrito = false; // xsw.writeEndDocument(); break; // FIN DE ELEMENTO case XMLStreamReader.END_ELEMENT: if (URI.equals("") &&

(37)

primerElemento.equals(xsr.getLocalName())) parar = true;

escrito = true;

// xsw.writeEndElement();

xsw.writeCharacters(xsr.getLocalName());

//Elimina de la lista el espacio de nombres de elemento

//finalizado

nombres.remove(nombres.size()-1);

// Identifica si finaliza el elemento Signature para activar

// los correspondientes flags

if (xsr.getLocalName().equals("Signature")) { signature = false;

finsignature = true;

}// Identifica si acaba el elemento referenciado por el

// uri, activando el flag correspondiente

else if (eltoreferenciado.equals(xsr.getLocalName())) { finencontrado = true; } break; // DECLARACIÓN DE ENTIDAD case XMLStreamReader.ENTITY_DECLARATION: escrito = false; break; // REFERENCIA A ENTIDAD case XMLStreamReader.ENTITY_REFERENCE: escrito = true; xsw.writeEntityRef(xsr.getText()); break; // ESPACIO DE NOMBRES case XMLStreamReader.NAMESPACE: escrito = true; xsw.writeNamespace(xsr.getPrefix(), xsr.getNamespaceURI()); break; // DECLARACIÓN DE NOTACIÓN case XMLStreamReader.NOTATION_DECLARATION: escrito = false; break; // INSTRUCCIÓN

(38)

case XMLStreamReader.PROCESSING_INSTRUCTION: escrito = true; xsw.writeProcessingInstruction(xsr.getPITarget(), xsr .getPIData()); break; // ESPACIO EN BLANCO case XMLStreamReader.SPACE: if (escrito) { xsw.writeCharacters(Firma.FIN_LINEA); escrito = false; } break; // COMIENZO DE DOCUMENTO case XMLStreamReader.START_DOCUMENT: escrito = false; break; // COMIENZO DE ELEMENTO case XMLStreamReader.START_ELEMENT: if (primerElemento.equals("")) // almacena el valor del // primer elto. USADO // para ENVELOPED primerElemento = xsr.getLocalName(); // Activa el flag si se comienza el elemento Signature if (xsr.getLocalName().equals(Firma.SIGNATURE)) { signature = true; } escrito = true; xsw.writeStartElement(xsr.getPrefix() == null ? "" : xsr .getPrefix(), xsr.getLocalName(), xsr .getNamespaceURI()); escribeNamespaces(nombres,xsr,xsw);

int attrs = xsr.getAttributeCount(); if (attrs > 0) {

ArrayList atributos = new ArrayList(); ArrayList atributosuri = new ArrayList(); ArrayList listaindex = new ArrayList();

(39)

String [] elemento = new String[2]; elemento[0] = String.valueOf(j); if(xsr.getAttributeNamespace(j)=="") { atributos.add(xsr.getAttributeLocalName(j)); elemento[1] =xsr.getAttributeLocalName(j); }else { atributosuri.add(xsr.getAttributeNamespace(j)+"="+ xsr. getAttributeLocalName(j)); elemento[1] =xsr.getAttributeNamespace(j)+"="+ xsr. getAttributeLocalName(j); } listaindex.add(elemento); if (xsr.getAttributeLocalName(j).toUpperCase() .equals(Firma.ID) && this.URI.equals("#"

+ xsr.getAttributeValue(j))) { encontrado = true; eltoreferenciado = xsr.getLocalName(); } } if(atributos.size()>0){ String [] attr = new

String[atributos.size()];

for (int i = 0; i <atributos.size() ; i++)

{

attr[i] = (String)atributos.get(i); }

quickSort(attr, attr.length);

for (int i = 0; i <attr.length ; i++) { int indexencontrado = -1; String [] eltosalida; for (int j = 0; j <listaindex.size() ; j++) { eltosalida = (String[])listaindex.get(j); if(attr[i].equals(eltosalida[1])) { indexencontrado = j;

(40)

xsw.writeAttribute(xsr.getAttributePrefix(Integer.parseInt(eltosalida[ 0]))==null ? "" : xsr.getAttributePrefix(Integer.parseInt(eltosalida[0])), xsr.getAttributeNamespace(Integer.parseInt(eltosalida[0])), xsr.getAttributeLocalName(Integer.parseInt(eltosalida[0])),normalizar_ espacios(xsr. getAttributeValue(Integer.parseInt(eltosalida[0])))); } } if(indexencontrado!=-1) listaindex.remove(indexencontrado); } } if(atributosuri.size()>0){ String [] attruri = new

String[atributosuri.size()];

for (int i = 0; i <atributosuri.size() ; i++) { attruri[i] = (String)atributosuri.get(i); } quickSort(attruri, attruri.length);

for (int i = 0; i <attruri.length ; i++)

{

int indexencontradouri = -1; String [] eltosalidauri;

for (int j = 0; j <listaindex.size() ; j++) { eltosalidauri = (String[])listaindex.get(j); if(eltosalidauri[1].equals(attruri[i])) { indexencontradouri = j; xsw.writeAttribute(xsr.getAttributePrefix(Integer.parseInt(eltosalidau ri[0]))==null ? "" : xsr.getAttributePrefix(Integer.parseInt(eltosalidauri[0])), xsr.getAttributeNamespace(Integer.parseInt(eltosalidauri[0])), xsr.getAttributeLocalName(Integer.parseInt(eltosalidauri[0])),normaliz ar_espacios(xsr.

(41)

getAttributeValue(Integer.parseInt(eltosalidauri[0])))); } } if(indexencontradouri!=-1) listaindex.remove(indexencontradouri); } } } break; } if (escrito) { xsw.flush(); eventcadena = sw.toString(); if (xsr.getEventType() == XMLStreamReader.START_ELEMENT) eventcadena += ">"; else if (xsr.getEventType() == XMLStreamReader.END_ELEMENT) eventcadena = "</" + eventcadena + ">"; }

// Si es Enveloped, se firma todo el documento salvo la firma

if (this.URI.equals("")) {

if (escrito && !primerElemento.equals("") && !signature && !finsignature) {

// ACTUALIZA EL RESUMEN

resumen.update(eventcadena.getBytes("UTF-8"), 0,

eventcadena.getBytes("UTF-8").length);

}

} else { // Si no es Enveloped sólo se añade al resumen el

// elemento referenciado por URI

if (escrito && encontrado) { // ACTUALIZA EL RESUMEN

resumen.update(eventcadena.getBytes("UTF-8"), 0,

eventcadena.getBytes("UTF-8").length);

}

}

}// TOMA EL SIGUIENTE EVENTO

xsr.next();

// Devuelve al valor inicial el flag si se ha leido el final de

(42)

if (finsignature)

finsignature = false;

// Devuelve al estado inicial los flags de elemento referenciado // al finalizar éste. if (finencontrado) { encontrado = false; finencontrado = false; } }

// Cerrar los flujos

xsr.close(); flujoin.close();

// CÁLCULO DEL RESUMEN FINAL

resumen.doFinal(byteresumen, 0);

// Asigna el valor calculado a DigestValue

DigestValue = byteresumen;

} catch (XMLStreamException e) {

System.err.print("Error de flujo XML:" +e.getMessage()); return false;

} catch (UnsupportedEncodingException e) { System.err.print("Error de codificación:"

+e.getMessage());

return false;

} catch (IOException e) {

System.err.print("Error cerrando flujo de entrada:"

+e.getMessage());

return false; }

// Compara el valor de resumen calculado con el que resumen recibido

if (DigestValue.length != digestsinvalidar.length) { valido = false;

} else {

for (int i = 0; i < digestsinvalidar.length; i++) { if (DigestValue[i] != digestsinvalidar[i]) valido = false; } } return valido; }

/** Devuelve el flujo sobre el que se calcula el resumen**/

public InputStream getDigestInputStream() {

return this.flujoin; }

/** Devuelve el URI de ésta referencia **/

public String getURI() {

(43)

}

/** Devuelve una lista de transformaciones**/

public ArrayList getTransforms() {

return this.transforms; }

/** Codifica un String en UTF-8 */

public String toUTF8(String entrada) {

String formato = ""; try{

formato = new String(entrada.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) {

System.err.print("Error de codificación:"

+e.getMessage());

return entrada; }

return formato; }

/**Devuelve el String de entrada con los espacios en blanco normalizados.

* Elimina espacios en blanco consecutivos, dejando un espacio simple

* **/

public String normalizar_espacios(String valor) { String devolver = "";

if (valor != "") {

char[] entrada = valor.toCharArray(); char[] salida = new char[entrada.length]; int j = 0;

for (int i = 0; i < entrada.length; i++) {

if ((i == 0) || (entrada[i] != ' ') || (entrada[i - 1] != ' ')) {

salida[j] = entrada[i]; j++;

} }

devolver = new String(salida, 0, j);

}

devolver = toUTF8(devolver); return devolver;

}

/**Ordena lexicográficamente un String [] **/

public static void quickSort(String numbers[], int array_size) { q_sort(numbers, 0, array_size - 1);

}

/**Se usa en la ordenación lexicográfica**/

public static void q_sort(String numbers[], int left, int right) { String pivot;

Referencias

Documento similar

Also, it is possible to appreciate that the surveyed that do use exfoliants tend to believe that marble adds value to an exfoliating cream, this shows that there is a market for

Siendo el Covid-19 una enfermedad altamente contagiosa y una pandemia que afecta la sostenibilidad social, política y económica de muchos países en el mundo; nuestro país no ha

Las nuevas posibilidades en el acceso, almacenamiento y utilización de la información han motivado una toma de conciencia sobre el valor de la información en el ámbito

La petición la recibe el módulo Notificación del Proveedor el cual se la pasa a Procesamiento para que éste con el XML que contiene la descripción del pedido genere un

En el capítulo 2: Descripción de las tecnologías para la solución, se describen las tecnologías utilizadas para la comunicación del mundo virtual con el resto

El programador de la seguridad del SIGEP, para llevar a cabo el trabajo de identificar los recursos de la aplicación, debe chequear todos los archivos XML que controlan

Descripción General: La misma tiene el objetivo serializar a xml los datos asociados a un atributo de un objeto de la base de datos y obtener estos datos a partir del mismo xml.

Para la creación final del componente instalable hay simplemente que generar un archivo XML con nombre igual al del componente y con un formato específico, en este se