/*
* The MIT License
*
* Copyright 2014, 2015, 2016 Rui Martinho (rmartinho@gmail.com), António Braz (antoniocbraz@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.poreid.cc;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.ResourceBundle;
import org.poreid.POReIDException;
import org.poreid.SmartCardFileException;
import org.poreid.dialogs.pindialogs.PinBlockedException;
import org.poreid.dialogs.pindialogs.PinEntryCancelledException;
import org.poreid.dialogs.pindialogs.PinTimeoutException;
/**
* Fornece a implementação das funcionalidades definidas na interface CitizenData
* @author POReID
*/
public abstract class CitizenCard extends POReIDCard implements CitizenData{
private String visibleInfo;
private String tooltip;
private String description;
private final ResourceBundle bundle;
private CitizenCardIdAttributes ccia = null;
private CitizenCardPhotoAttributes ccpa = null;
private CitizenCardAddressAttributes ccaa = null;
private byte[] notes = null;
private byte[] sod = null;
protected CitizenCard(CardSpecificReferences csr) {
super(csr);
bundle = CCConfig.getBundle(CitizenCard.class.getSimpleName(),csr.getLocale());
}
@Override
public final CitizenCardPhotoAttributes getPhotoData() throws SmartCardFileException {
try {
if (null != ccpa){
return ccpa;
}
return ccpa = new CitizenCardPhotoAttributes(readFile(getFileDescription().PHOTO));
} catch (PinTimeoutException | PinEntryCancelledException | PinBlockedException | POReIDException ex) {
throw new SmartCardFileException("Erro durante a leitura da fotografia. Não foi possivel ler os dados.", ex);
}
}
@Override
public final CitizenCardIdAttributes getID() throws SmartCardFileException {
try {
if (null != ccia){
return ccia;
}
return ccia = new CitizenCardIdAttributes(readFile(getFileDescription().ID));
} catch (PinTimeoutException | PinEntryCancelledException | PinBlockedException | POReIDException ex) {
throw new SmartCardFileException("Erro durante a leitura da identificação. Não foi possivel ler os dados.", ex);
}
}
@Override
public final CitizenCardAddressAttributes getAddress() throws PinTimeoutException, PinEntryCancelledException, PinBlockedException, POReIDException {
if (null != ccaa) {
return ccaa;
}
return ccaa = new CitizenCardAddressAttributes(readFile(getFileDescription().ADDRESS));
}
@Override
public final byte[] readPersonalNotes() throws SmartCardFileException {
try {
if (null != notes){
return notes;
}
return notes = readFile(getFileDescription().NOTES);
} catch (PinTimeoutException | PinEntryCancelledException | PinBlockedException | POReIDException ex) {
throw new SmartCardFileException("Erro durante a leitura das notas pessoais. Não foi possivel ler os dados.", ex);
}
}
@Override
public final byte[] getSOD() throws SmartCardFileException {
try {
if (null != sod){
return sod;
}
return sod = readFile(getFileDescription().SOD);
} catch (PinTimeoutException | PinEntryCancelledException | PinBlockedException | POReIDException ex) {
throw new SmartCardFileException("Erro durante a leitura do SOD. Não foi possivel ler os dados.", ex);
}
}
@Override
public final String getUIVisibleInfo(){
if (visibleInfo == null){
try {
getID();
} catch (SmartCardFileException ex) {
throw new RuntimeException("Erro não é possivel exibir os dados do cartão.", ex);
}
visibleInfo = ccia.getCitizenFullName();
}
return visibleInfo;
}
@Override
public final String getTooltip(){
if (tooltip == null){
try {
getID();
} catch (SmartCardFileException ex) {
return bundle.getString("tooltip.error");
}
tooltip = bundle.getString("name")+": " + ccia.getCitizenFullName()+" * "+bundle.getString("nic")+": "+ccia.getDocumentNumber();
}
return tooltip;
}
@Override
public final String getDescription() {
if (null == description) {
try {
getID();
} catch (SmartCardFileException ex) {
return bundle.getString("description.error");
}
description = MessageFormat.format(bundle.getString("description"), ccia.getCitizenFullName(), ccia.getDocumentNumber());
}
return description;
}
@Override
public final void savePersonalNotes(String notes) throws SmartCardFileException, PinTimeoutException, POReIDException, PinEntryCancelledException, PinBlockedException {
byte[] tmp = notes.getBytes(StandardCharsets.UTF_8);
byte[] notesBytes;
if (tmp.length+1 > getFileDescription().NOTES.getMaximumSize()){
throw new SmartCardFileException("O tamanho dos dados excede a capacidade das notas pessoais. Tamanho máximo = "+getFileDescription().NOTES.getMaximumSize()+" bytes");
}
notesBytes = new byte[tmp.length+1];
System.arraycopy(tmp, 0, notesBytes, 0, tmp.length);
notesBytes[tmp.length] = '\0';
writeFile(getFileDescription().NOTES, notesBytes);
}
@Override
public PublicKey getPublicKey() throws SmartCardFileException, InvalidKeySpecException, NoSuchAlgorithmException {
try {
PublicKey pubKey;
byte[] pk;
pk = readFile(getFileDescription().PUBLIC_KEY);
BigInteger modulus = new BigInteger(Arrays.copyOf(pk, 128));
BigInteger exponent = new BigInteger(Arrays.copyOfRange(pk, 128, pk.length));
RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory factory = KeyFactory.getInstance(CCConfig.RSA);
pubKey = factory.generatePublic(spec);
return pubKey;
} catch (PinEntryCancelledException | PinBlockedException | POReIDException | PinTimeoutException ex) {
throw new SmartCardFileException("Erro durante a leitura da chave pública. Não foi possivel ler os dados.", ex);
}
}
}