jueves, 18 de febrero de 2010

Como obtener el sello digital con JAVA

Hola el objetivo de esta entrada es explicar cómo crear un sello digital, para la facturación electrónica.

Escribo esto porque tuve muchos problemas para poder crearlo, mi primer problema fue el poder leer la llave privada que te da el SAT, ya que esta viene ecriptada con un password y encontré poca información de como leerla en java.

Bueno, basta de quejas, empecemos!

Lo primero que hay que hacer es generar la cadena original, la creación de esta cadena esta especificada en el anexo 20 de la Resolución Miscelánea Fiscal inciso D. Esta es una cadena formada con los datos de la factura, estos datos están separados por el carácter pipe ”|”, y se inicia y finaliza esta cadena con un doble pipe “||”.
Aquí le s dejo un ejemplo de la cadena Original.

||2.0|AB|32|2010-02-18T12:30:03|434|2006|ingreso|EFECTIVO|3000.00|45029.85|02934INFOSOFT|Infosoft & Xgress|arenas|98|Coyoacan|DF|México|54832|4503495WXGF4|México|2|Impresoras|1500.00|3000.00|2|PC|2000.00|4000.00|IVA|15.00|2900.85|2900.85||

Ya que tenemos la cadena original lo siguiente es pasarla por un algoritmo de digestión como es el MD5, y el resultado pasarlo por un algoritmo de encriptación RSA, estos dos pasos se pueden hacer en uno solo con el api de java. Para esto lo primero que necesitamos es la clave privada (archivo.key) que nos proporcionó el SAT junto con su password. Esta clave esta codificada según el estándar PKCS8 en formato DER. Además esta clave esta encriptada con un password.
Para poder des enriptarla utilizaremos la librería commons-ssl de apache. De esa libraría utilizaremos el objeto PKCS8Key de la siguiente manera:

PKCS8Key pkcs8 = new PKCS8Key(clavePrivada, password.toCharArray());

Donde clavePrivada es un arreglo de bytes que contiene la clave privada.
Para poder obtener la clave privada solo se la pedimos a este objeto:

java.security.PrivateKey pk = pkcs8.getPrivateKey();

Lo siguiente que hay que hacer es obtener el objeto que codificara en MD5 y RSA nuestra cadena, e inicializarlo con la clave privada este es java.security.Signature.

Signature firma = Signature.getInstance("MD5withRSA");
firma.initSign(pk);

donde pk es la clave privada que obtuvimos.
Al objeto Signature se le pasa la cadena original convertida en bytes con formato UFT-8
firma.update(cadenaOriginal.getBytes("UTF-8"));
y obtenemos el arreglo de bytes con la cadena original encriptada.

byte[] cadenaFirmada = firma.sign();

A continuación se codifica en base 64 la cadena para poder obtener caracteres imprimibles con el objeto sun.misc.BASE64Encoder.

BASE64Encoder b64 = new BASE64Encoder();
String selloDigital = b64.encode(firma.sign());

Y con esto obtenemos una cadena como esta que es el sello digital

UdjknEGo/r0v7QrAhvL+aFKkl6Jk6b4pNvRYI0ymWrW19k4DjzygbtTnAnB0HNmafifTNzxB+/wE
JsJKGWjbnSAO61gy6JTLSvrdS+KPKpQtxYH8/7Ib55J8T4PuIL0a6qmAwpMFrHToSaAO0NXG3W9t
homWp8b+UdbJ2qL/ABI=

Les dejo el código completo para que lo revisen.


package com.infosoft.rasengan.cfd;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.Signature;

import org.apache.commons.ssl.PKCS8Key;
import org.jdom.Document;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.output.Format.TextMode;

import sun.misc.BASE64Encoder;

import com.infosoft.rasengan.cfd.bean.Comprobante;
/**
* Clase que genera el comprobante fiscal digital asi como el sello digital
* @author Xgress
*
*/
public class GeneradorCFD {

private Comprobante comprobante;

/**
* Constructor que inicializa el objeto con un Comprobante, genera el
* selloDigital y se lo agrega al objeto Comprobante
*
* @param comprobante
* Objeto que contiene todos los datos de un Comprobante Fiscal
* Digital
* @param archivoClavePrivada
* InputStream que contiene el archivo .key de la llave privada
* @param password
* String con el password de la llave privada
* @throws GeneralSecurityException
* Excepcion arrogada cuando el password no es el correcto
*/
public GeneradorCFD(Comprobante comprobante,
InputStream archivoClavePrivada, String password)
throws GeneralSecurityException {
this.comprobante = comprobante;
this.comprobante
.setSello(getSelloDigital(archivoClavePrivada, password));
}

/**
* Metodo que genera el sello digital a partir de la cadena original y la
* clave privada siguiendo los siguientes pasos: 1)Se le aplica la funcion
* hash de digestion MD5 a la cadena original y se aplica el algoritmo de
* encripcion RSA con la clave privada. 2) Se codifica el resultado a Base64
* teniendo como resultado una cadena imprimible.
*
* @param archivoClavePrivada
* InputStream que contiene la clave privada(archivo .key)
* @param password
* String con el password de la clave privada
* @return String con el sello digital
* @throws GeneralSecurityException
* Excepcion arrogada cuando el password no es el correcto
*/
public String getSelloDigital(InputStream archivoClavePrivada,
String password) throws GeneralSecurityException {
String cadenaOriginal = comprobante.getCadenaOriginal();
System.out.println(cadenaOriginal);
byte[] clavePrivada = getBytes(archivoClavePrivada);
PKCS8Key pkcs8 = new PKCS8Key(clavePrivada, password.toCharArray());
PrivateKey pk = pkcs8.getPrivateKey();
Signature firma = Signature.getInstance("MD5withRSA");
firma.initSign(pk);
String selloDigital = null;
try {
firma.update(cadenaOriginal.getBytes("UTF-8"));
BASE64Encoder b64 = new BASE64Encoder();
selloDigital = b64.encode(firma.sign());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.out.println(selloDigital);
return selloDigital;
}

/**
* Genera el xml extensible del comprobante fiscal digital
* @return String con el xml
*/
public String getCFD() {
Format format = Format.getPrettyFormat();
format.setEncoding("utf-8");
format.setTextMode(TextMode.NORMALIZE);
XMLOutputter xmlOutputer = new XMLOutputter(format);
String res = xmlOutputer
.outputString(new Document(comprobante.getXML()));
try {
res = new String(res.getBytes("UTF-8"));//TODO: probar bien
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return res;
}
/**
* Metodo que convierte un input stream con la llave privada a un array de bytes
* @param is InputSteam con la clave privada
* @return Arreglo de bytes con la clave privada
*/
private byte[] getBytes(InputStream is) {
int totalBytes = 714;
byte[] buffer = null;
try {
buffer = new byte[totalBytes];
is.read(buffer, 0, totalBytes);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return buffer;
}

}

jueves, 27 de agosto de 2009

martes, 7 de julio de 2009

Google se quita el tag "Beta"

Hoy se ha lanzado un anuncio desde el blog oficial de Google que nos dice que después de tan solo tres miseros años, Google ha decidido qutarle la etiqueta "BETA" a su paquete Google Apps, Gmail (Tan solo cinco años de ser beta, creí que moriría sin pasar a algo estable.), Docs, Calendar y Talk han dejado de ser aplicaciones feas e inestables. Pero si se preguntan que va a pasar, pues la respuesta es si, siguen siendo gratuitos para que no se pongan a gritar antes de tiempo.

Así que la proxima vez que Gmail te deje sin tus correos, podrás lanzar un par de recordatorios familiares. Al fin y al cabo, ya no servira la excusa "Esta en fase beta, suele pasar..." O eso dice la teoria.

lunes, 1 de junio de 2009

COBOL llega su mitad de siglo.



Hace 50 años nació gracias a la comisión CODASYL y el Departamento de Defensa de los Estados Unidos, Su nombre: COBOL (COmmon Business-Oriented Language)

La idea nació de Grace Murray Hopper, un científico y militar norteamericana, que buscaba crear un lenguaje de programación fácil de comprender. Y por ello se le considera como la madre de COBOL.

El primer boceto de Cobol fue presentado formalmente en el año de 1960 y su actual estandarización fue dada hasta el 2002. Con esto nace el divorcio entre software y Hardware.

Y pensar que a 50 años de su nacimiento se sigue usando principalmente en la banca para los cajeros automaticos o pago con tarjetas de credito. La realidad es que para los corporativos les resulta caro y laborioso migrar sus sistemas a otra plataforma y aun mas dificil se vuelve encontrar programadores en COBOL, ya me imagino a estos corporativos de visita a los museos en busca de algún fósil de programador para tratar de clonarlo.

Aunque Cobol es considerado a menudo un lenguaje mainframe algo anticuado, lo cierto es que en lo absoluto es obsoleto.

domingo, 24 de mayo de 2009

Leonidas se retrasa una semana

Que les puedo decir. Jesse Keating de la Red Hat ha dicho 'No hay leonidas' para este 26 de mayo. Por lo que ha anunciado que se retraza una semana (7 días) para darle a los 24 bugs detectados en las versiones de prueba. Pero mientras esto pasa y nos tienen como novia de pueblo hasta el 2 de junio, podemos matar el tiempo en la discución de cual será el nombre de la próxima versión del diestro (el numero 12), ¿alguien dijo yo?

domingo, 17 de mayo de 2009

IBM lanza su FaceBook para developers!!


Ahora que me he dedicado a programar en java y sus derivados, una de las paginas de donde hecho mano es DeveloperWorks, el cual es una de las principales fuentes de desarrollo para estándares abiertos de IBM, y que tiene muchas cosas muy bonitas y la verdad es que ya estoy inscrito como todo buen developer!!

Ahora IBM ha anunciado la incorporación del software sociales al portal de DeveloperWorks. My developerWorks, que es como han denominado al área denuevas funcionalidades que conbina lo mejor de las redes sociales con los recursos de DeveloperWorks, el cual permitira a los desarrolladores acceder en tiempo real a lo último en las actualizaciones tecnológias, conectarse con otros gurus de todo el mundo, por lo que la optención de conocimientos será con mayor rapidez.

Esta herramienta nos permite configurar cada perfil agregando contactos, contenido, comentarios de foros, blogs y wikis. En el transcurso de los proximos mesess, los felices usuarios de My DeveloperWorks podrán usar sus perfiles de redes sociales como twitter o facebook para ampliar sus red de maldar (Profecional) y poder colavorar con nuevas tecnologías.

Citando a los chicos de DirarioTI:

"IBM realizó recientemente una encuesta entre cientos de desarrolladores de todo el mundo para averiguar cómo utilizan los recursos online. Casi tres cuartas partes de los encuestados admitieron que usan foros, blogs, wikis y boletines de Internet para aumentar sus conocimientos y comunicarse con los amigos y cerca de un 65% expresaron su deseo de usar funcionalidades de redes sociales, como las que se encuentran en Facebook, Twitter y MySpace.
"

Fuente: DirarioTI

Re-lanzamiento de Linux.com


Después de que Linux.com quedara botado por SourceForge Inc y sin que ni un alma le hiciera caso mas que la Linux Foundation. Estos niños sin fines le lucro ha anunciado el RE-lanzamiento formal de Linux.com

El nuevo sitio estara enfocado a la promoción de la participación de todos los usuarios, por lo que entre mas se participe, más puntos ganaran, con lo cual podrán participar en el concurso anual "Ultimate Linux Guru" por una flameante notebook autografiada por el mismo Linus Torvalds. (Las bolsas se ganan por separado)

Así que será una muy buena idea entrar a rescatar esta pagina que por años nos dío tanto.