/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* Copyright (c) 2013, MPL CodeInside http://codeinside.ru
*/
package ru.codeinside.sign;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import static javax.xml.bind.DatatypeConverter.printBase64Binary;
final class Signer implements CertConsumer {
final private Vaadin vaadin;
final private Panel ui;
final Filter filter;
private PrivateKey privateKey;
private Signature signature;
private final Label label = new Label("Запуск...");
Signer(Vaadin vaadin, Panel ui, byte[] x509) {
this.vaadin = vaadin;
this.ui = ui;
filter = new EqualsFilter(x509);
}
Signer(Vaadin vaadin, Panel ui) {
this.vaadin = vaadin;
this.ui = ui;
filter = new AcceptAll();
}
private int currentBlock;
private int blocksCount;
private int currentChunk;
private int chunksCount;
public void ready(final String name, PrivateKey privateKey, X509Certificate certificate) {
this.privateKey = privateKey;
currentBlock = 0;
blocksCount = 0;
currentChunk = 0;
chunksCount = 0;
ui.removeAll();
ui.add(new Label(name), BorderLayout.PAGE_START);
ui.add(label, BorderLayout.CENTER);
Button prev = new Button("Отменить");
Panel panel = new Panel(new BorderLayout(2, 2));
panel.add(prev, BorderLayout.LINE_START);
ui.add(panel, BorderLayout.PAGE_END);
prev.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
loading();
}
});
ui.validate();
ui.repaint();
notifyReady(certificate);
}
@Override
public void loading() {
vaadin.updateVariable("state", "loading");
ui.removeAll();
ui.add(new Label("Загрузка сертификатов..."), BorderLayout.LINE_START);
Label label = new Label("");
ui.add(label, BorderLayout.CENTER);
ui.validate();
ui.repaint();
new Thread(new CertDetector(this, ui, label)).start();
}
public void refresh() {
ui.validate();
ui.repaint();
}
@Override
public void noJcp() {
ui.removeAll();
ui.add(new Label("Библиотека JCP не установлена."), BorderLayout.LINE_START);
refresh();
vaadin.updateVariable("state", "noJcp");
}
@Override
public Filter getFilter() {
return filter;
}
@Override
public String getActionText() {
return "Подписать";
}
@Override
public String getSelectionLabel() {
return "Текущий сертификат:";
}
public void block(int num, int total) {
currentBlock = num;
blocksCount = total;
currentChunk = 0;
chunksCount = 0;
try {
signature = Signature.getInstance("GOST3411withGOST3410EL");
signature.initSign(privateKey);
notifyBlock(currentBlock);
} catch (NoSuchAlgorithmException e) {
fail(e);
} catch (InvalidKeyException e) {
fail(e);
}
}
public void chunk(final int num, final int total, final byte[] bytes) {
currentChunk = num;
chunksCount = total;
try {
signature.update(bytes);
if (num != total) {
notifyChunk(currentChunk);
} else {
final byte[] signed = signature.sign();
signature = null;
notifySign(signed);
}
} catch (SignatureException e) {
fail(e);
}
}
private void fail(final Exception e) {
label.setText("Ошибка: " + e.getMessage());
refresh();
final StringWriter w = new StringWriter();
e.printStackTrace(new PrintWriter(w));
vaadin.updateVariable("fail", w.toString());
}
private void notifyBlock(int i) {
vaadin.updateVariable("block", i);
float complete = 100f * i / blocksCount;
label.setText(((int) complete) + "%");
refresh();
}
private void notifyChunk(int i) {
vaadin.updateVariable("chunk", i);
float big = 100f * currentBlock / blocksCount;
float small = 100f / blocksCount * i / chunksCount;
float complete = big + small;
label.setText(((int) complete) + "%");
refresh();
}
private void notifySign(final byte[] b) {
vaadin.updateVariable("sign", printBase64Binary(b));
float complete = 100f * currentBlock / blocksCount;
label.setText(((int) complete) + "%");
refresh();
}
private void notifyReady(final X509Certificate c) {
try {
vaadin.updateVariable("cert", printBase64Binary(c.getEncoded()));
label.setText("Получение данных с СИУ для подписания...");
refresh();
} catch (CertificateEncodingException e) {
fail(e);
}
}
}