es.logongas.util.seguridad.CodigoVerificacionSeguro.java Source code

Java tutorial

Introduction

Here is the source code for es.logongas.util.seguridad.CodigoVerificacionSeguro.java

Source

/*
 * Copyright 2013 Lorenzo Gonzlez.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package es.logongas.util.seguridad;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.LuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.oned.Code39Writer;
import com.google.zxing.qrcode.QRCodeReader;
import com.google.zxing.qrcode.QRCodeWriter;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Random;
import javax.imageio.ImageIO;
import org.apache.commons.codec.binary.Base32;

/**
 * Clase para la generacion de cdigo nicos de verificacion seguros.
 *
 * @author Lorenzo Gonzlez
 */
public class CodigoVerificacionSeguro {

    //OJO:Si se cambia el nombre de la variable se debe cambiar tambien algn hbm de persistencia de Hiebrante.
    private String valor;

    private CodigoVerificacionSeguro() {
        //Lo necesita Hibernate
    }

    private CodigoVerificacionSeguro(String valor) {
        this.valor = valor;
    }

    /**
     * Crea un cdigo de verificacin seguro nico en base al String con el
     * valor
     *
     * @param valor Este valor se obtiene de unba instancia de llamar al mtodo
     * getValor()
     * @return El cdigo de verificacin seguro
     */
    public static CodigoVerificacionSeguro getInstance(String valor) {
        return new CodigoVerificacionSeguro(valor.toUpperCase());
    }

    /**
     * Crea un cdigo de verificacin seguro nico
     *
     * @param key La clave del documento.
     * @return El cdigo de verificacin seguro
     */
    public static CodigoVerificacionSeguro getInstance(int key) {
        return new CodigoVerificacionSeguro(createValor(key));
    }

    /**
     * Crea un cdigo de verificacin seguro nico a paritr de una imagen que
     * est en un array de datos
     *
     * @param imageInputStream Los bytes de la imagen
     * @return El cdigo de verificacin seguro
     */
    public static CodigoVerificacionSeguro getInstanceFromImageQRCode(InputStream imageInputStream) {
        try {
            BufferedImage originalImage = ImageIO.read(imageInputStream);
            BufferedImage image = resizeImage(originalImage, 0.5); //Hacemos mas pequea la imagen pq sino no lee bien el cdigo.
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

            QRCodeReader qRCodeReader = new QRCodeReader();
            Result result = qRCodeReader.decode(bitmap);

            return new CodigoVerificacionSeguro(String.valueOf(result.getText()));
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public String getValor() {
        return valor;
    }

    public int getKey() {
        try {
            Base32 base32 = new Base32();
            byte datos[] = base32.decode(valor);
            DataInputStream dataInputStream = new DataInputStream(new ByteArrayInputStream(datos));
            int key = dataInputStream.readInt();

            return key;
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

    public boolean isValido() {
        try {
            Base32 base32 = new Base32();
            byte datos[] = base32.decode(valor);
            DataInputStream dataInputStream = new DataInputStream(new ByteArrayInputStream(datos));
            int key = dataInputStream.readInt();
            int numeroAleatorio = dataInputStream.readInt();
            int crcReal = dataInputStream.readInt();

            CRC crc = new CRC();
            crc.update(key).update(numeroAleatorio);

            if (crcReal == crc.getCRC()) {
                return true;
            } else {
                return false;
            }
        } catch (IOException ex) {
            return false;
        }
    }

    private static String createValor(int key) {
        try {
            //Generar el N aleatorio
            int numeroAleatorio = new Random().nextInt(Integer.MAX_VALUE);
            CRC crc = new CRC();
            crc.update(key).update(numeroAleatorio);

            //Genera el array de datos con el tipo, key y el n aleatorio
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
            dataOutputStream.writeInt(key);
            dataOutputStream.writeInt(numeroAleatorio);
            dataOutputStream.writeInt(crc.getCRC());

            byte[] datos = byteArrayOutputStream.toByteArray();

            //Trasformarlo en un String en Base32
            Base32 base32 = new Base32();
            String codigoVerificacionSeguro = base32.encodeAsString(datos);

            //Quitamos el "=" del final pq no se puedo codificar con el cdigo de barras.
            codigoVerificacionSeguro = codigoVerificacionSeguro.substring(0, codigoVerificacionSeguro.indexOf('='));

            return codigoVerificacionSeguro;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }

    }

    /**
     * Genera una imagen en formato PNG con un cdigo de barras del cdigo de
     * verificacin seguro
     *
     * @param ancho Ancho en pxeles de la imagen generada
     * @param alto Alto en pxeles de la imagen generada
     * @return Los bytes de la imagen del cdigo de barras en formato PNG
     */
    public byte[] getBarCode(int ancho, int alto) {
        try {
            Code39Writer writer = new Code39Writer();
            BitMatrix bitMatrix = writer.encode(valor, BarcodeFormat.CODE_39, ancho, alto);
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            MatrixToImageWriter.writeToStream(bitMatrix, "png", byteArrayOutputStream);

            return byteArrayOutputStream.toByteArray();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * Genera una imagen en formato PNG con un cdigo QR del cdigo de
     * verificacin seguro
     *
     * @param tamanyo tamanyo del lado en pxeles de la imagen generada. La
     * iamgen es cuadrada
     * @return Los bytes de la imagen del cdigo QR en formato PNG
     */
    public byte[] getQRCode(int tamanyo) {
        try {
            QRCodeWriter writer = new QRCodeWriter();
            BitMatrix bitMatrix = writer.encode(valor, BarcodeFormat.QR_CODE, tamanyo, tamanyo);
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            MatrixToImageWriter.writeToStream(bitMatrix, "png", byteArrayOutputStream);

            return byteArrayOutputStream.toByteArray();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * Esta funcin se aplica pq para imagenes muy grandes no reconoce el cdigo
     * QR
     *
     * @param originalImage La imagen original
     * @param f El factor de escalado
     * @return La iamgen reescalada.
     */
    private static BufferedImage resizeImage(BufferedImage originalImage, double f) {
        int ancho = (int) (((double) originalImage.getWidth()) * f);
        int alto = (int) (((double) originalImage.getHeight()) * f);
        int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
        BufferedImage resizedImage = new BufferedImage(ancho, alto, type);
        Graphics2D g = resizedImage.createGraphics();
        g.drawImage(originalImage, 0, 0, ancho, alto, null);
        g.dispose();

        return resizedImage;
    }
}