Validación de huella digitalValidación de huella digitalhttps://centroderecursos.agesic.gub.uy/c/message_boards/find_thread?p_l_id=33353&threadId=505412024-03-28T10:51:16Z2024-03-28T10:51:16ZRE: Validación de huella digitalOsvaldo Grassohttps://centroderecursos.agesic.gub.uy/c/message_boards/find_message?p_l_id=33353&messageId=2502862018-06-23T23:14:12Z2018-06-23T23:14:12Zhola, tengo exactamente el mismo problema, y queria validar que la huella funciona bien... será posible que corrijan el codigo que está subido en github (https://github.com/eIDuy/apdu-services)? <br /><br />tengo una tarjeta Especimen V3.Osvaldo Grasso2018-06-23T23:14:12ZRE: Validación de huella digitalGuillermo Dottahttps://centroderecursos.agesic.gub.uy/c/message_boards/find_message?p_l_id=33353&messageId=636252017-03-15T18:04:04Z2017-03-15T18:04:04ZDiego, cómo estás?<br /><br />Las minucias en el ejemplo publicado corresponden a algunas cédulas de prueba (están identificadas en el nombre de las variables) pero no necesariamente son las mismas ni se corresponden con la cédula de pruebas que tienes tú. No obstante, ahora contamos con un nuevo lote de pruebas en el cual las cédulas tienen identificada cuáles son las minucias correspondientes con que fueron personalizadas, con lo cual se puede probar con seguridad el Match-On-Card.<br /><br />Contamos con las minucias para probar solamente el acceso a los comandos de la cédula, y contamos con las imágenes de las huellas para probar también la extracción. Están a disposición para pedirlas.<br /><br />Por otra parte, el error que mencionas es de un buffer de nuestra implementación. Al ser una implementación de ejemplo y no una biblioteca para reutilizar directamente, puede que hayan algunas cosas que no estén del todo prolija. Nuevamente, su objetivo es ser un ejemplo y orientar la implementación, no ser una biblioteca cerrada y testeada. No me detendría mucho en ese error, porque puede ser un problema de que la tarjeta contesta algo que no estaba esperado nada más... Aquí te pongo el código de una implementación derivada del apdu-services que está probado que funciona. No contiene la parte de extracción de la minucia porque eso depende de qué proveedor de biometría estés usando, pero asumiendo que en el parámetro <em>minutiae</em> viene un string hexa con los bytes de la minucia ya extraída (formato ISO CC), funciona.<br /><br /><div class="lfr-code"><table><tbody><tr><td class="line-numbers" data-line-number="1"></td><td class="lines"><div class="line">private static boolean verifyFP(String minutiae) throws CardException, FileNotFoundException, UnsupportedEncodingException {</div></td></tr><tr><td class="line-numbers" data-line-number="2"></td><td class="lines"><div class="line"> </div></td></tr><tr><td class="line-numbers" data-line-number="3"></td><td class="lines"><div class="line"> //Inicializacion de la tarjeta</div></td></tr><tr><td class="line-numbers" data-line-number="4"></td><td class="lines"><div class="line"> TerminalFactory factory = TerminalFactory.getDefault();</div></td></tr><tr><td class="line-numbers" data-line-number="5"></td><td class="lines"><div class="line"> List<CardTerminal> terminals = factory.terminals().list();</div></td></tr><tr><td class="line-numbers" data-line-number="6"></td><td class="lines"><div class="line"> CardTerminal terminal = terminals.get(3);</div></td></tr><tr><td class="line-numbers" data-line-number="7"></td><td class="lines"><div class="line"> System.out.println(terminal.getName());</div></td></tr><tr><td class="line-numbers" data-line-number="8"></td><td class="lines"><div class="line"> Card card = terminal.connect("T=0");</div></td></tr><tr><td class="line-numbers" data-line-number="9"></td><td class="lines"><div class="line"> CardChannel channel = card.getBasicChannel();</div></td></tr><tr><td class="line-numbers" data-line-number="10"></td><td class="lines"><div class="line"> </div></td></tr><tr><td class="line-numbers" data-line-number="11"></td><td class="lines"><div class="line"> //select IAS</div></td></tr><tr><td class="line-numbers" data-line-number="12"></td><td class="lines"><div class="line"> selectIAS(channel);</div></td></tr><tr><td class="line-numbers" data-line-number="13"></td><td class="lines"><div class="line"> </div></td></tr><tr><td class="line-numbers" data-line-number="14"></td><td class="lines"><div class="line"> String CLASS = "00";</div></td></tr><tr><td class="line-numbers" data-line-number="15"></td><td class="lines"><div class="line"> String INSTRUCTION = "21";</div></td></tr><tr><td class="line-numbers" data-line-number="16"></td><td class="lines"><div class="line"> String PARAM1 = "00";</div></td></tr><tr><td class="line-numbers" data-line-number="17"></td><td class="lines"><div class="line"> String PARAM2 = "21";</div></td></tr><tr><td class="line-numbers" data-line-number="18"></td><td class="lines"><div class="line"><br /></div></td></tr><tr><td class="line-numbers" data-line-number="19"></td><td class="lines"><div class="line"> String dataIN = "";</div></td></tr><tr><td class="line-numbers" data-line-number="20"></td><td class="lines"><div class="line"> dataIN += "7F2E"; // TAG del TLV para llevar las minucias</div></td></tr><tr><td class="line-numbers" data-line-number="21"></td><td class="lines"><div class="line"> // Como el TLV hijo es minucias + length + value, entonces el largo de</div></td></tr><tr><td class="line-numbers" data-line-number="22"></td><td class="lines"><div class="line"> // este es largo(minucias) + 2</div></td></tr><tr><td class="line-numbers" data-line-number="23"></td><td class="lines"><div class="line"> int largo_value = 2 + minutiae.length() / 2;</div></td></tr><tr><td class="line-numbers" data-line-number="24"></td><td class="lines"><div class="line"> if (largo_value > 0x7F) {</div></td></tr><tr><td class="line-numbers" data-line-number="25"></td><td class="lines"><div class="line"> dataIN += "81";</div></td></tr><tr><td class="line-numbers" data-line-number="26"></td><td class="lines"><div class="line"> //Esto es porque dice que es una estructura BER-TLV, y se codificaria asi.</div></td></tr><tr><td class="line-numbers" data-line-number="27"></td><td class="lines"><div class="line"> //Cuando el largo pasa 0x7F, se tiene que poner el largo como 0x81XX, siendo XX el largo efectivo del contenido.</div></td></tr><tr><td class="line-numbers" data-line-number="28"></td><td class="lines"><div class="line"> }</div></td></tr><tr><td class="line-numbers" data-line-number="29"></td><td class="lines"><div class="line"> dataIN += Utils.byteArrayToHex(Utils.intToByteArray(largo_value)); </div></td></tr><tr><td class="line-numbers" data-line-number="30"></td><td class="lines"><div class="line"><br /></div></td></tr><tr><td class="line-numbers" data-line-number="31"></td><td class="lines"><div class="line"> // 81 aca es el tag del proximo TLV, y el length es el largo de las</div></td></tr><tr><td class="line-numbers" data-line-number="32"></td><td class="lines"><div class="line"> // minucias, que es el value</div></td></tr><tr><td class="line-numbers" data-line-number="33"></td><td class="lines"><div class="line"> // Puede que si el largo supera 0x7F también haya que poner el largo como 0x81XX por ser un BER-TLV.</div></td></tr><tr><td class="line-numbers" data-line-number="34"></td><td class="lines"><div class="line"> // Si falla con error 6A80, probar codificar el largo como 0x81XX (y cuidado que hay que ajustar el largo del TLV padre).</div></td></tr><tr><td class="line-numbers" data-line-number="35"></td><td class="lines"><div class="line"> dataIN += "81"</div></td></tr><tr><td class="line-numbers" data-line-number="36"></td><td class="lines"><div class="line"> + Utils.byteArrayToHex(Utils.intToByteArray(minutiae.length() / 2));</div></td></tr><tr><td class="line-numbers" data-line-number="37"></td><td class="lines"><div class="line"> dataIN += minutiae;</div></td></tr><tr><td class="line-numbers" data-line-number="38"></td><td class="lines"><div class="line"><br /></div></td></tr><tr><td class="line-numbers" data-line-number="39"></td><td class="lines"><div class="line"> byte CLASSbyte = Utils.hexStringToByteArray(CLASS)[0];</div></td></tr><tr><td class="line-numbers" data-line-number="40"></td><td class="lines"><div class="line"> byte INSbyte = Utils.hexStringToByteArray(INSTRUCTION)[0];</div></td></tr><tr><td class="line-numbers" data-line-number="41"></td><td class="lines"><div class="line"> byte P1byte = Utils.hexStringToByteArray(PARAM1)[0];</div></td></tr><tr><td class="line-numbers" data-line-number="42"></td><td class="lines"><div class="line"> byte P2byte = Utils.hexStringToByteArray(PARAM2)[0];</div></td></tr><tr><td class="line-numbers" data-line-number="43"></td><td class="lines"><div class="line"> ResponseAPDU r = Utils.sendCommand(channel, CLASSbyte, INSbyte, P1byte, P2byte, Utils.hexStringToByteArray(dataIN),0);</div></td></tr><tr><td class="line-numbers" data-line-number="44"></td><td class="lines"><div class="line"> </div></td></tr><tr><td class="line-numbers" data-line-number="45"></td><td class="lines"><div class="line"> // disconnect</div></td></tr><tr><td class="line-numbers" data-line-number="46"></td><td class="lines"><div class="line"> card.disconnect(false);</div></td></tr><tr><td class="line-numbers" data-line-number="47"></td><td class="lines"><div class="line"> </div></td></tr><tr><td class="line-numbers" data-line-number="48"></td><td class="lines"><div class="line"> return (r.getSW1() == (int) 0x90 && r.getSW2() == (int) 0x00); </div></td></tr><tr><td class="line-numbers" data-line-number="49"></td><td class="lines"><div class="line"> }</div></td></tr></tbody></table></div><br />En caso de bloqueo de la huella dactilar por reintentos, no se puede desbloquear, el perfil de la tarjeta no lo permite por seguridad. Es por eso que hay que tener mucho cuidado en las pruebas de implementación del MOC y se recomienda usar cédulas de prueba.<br />En caso de bloqueo de PIN numérico para firma digital, se puede desbloquear pero no sin la ayuda de la DNIC, nuevamente por seguridad. Si sucede esto con una cédula propia, se puede ir a cualquier DNIC a pedir un desbloqueo de PIN, es un trámite de 2 minutos. Si sucede con cédulas de prueba, se puede también pero en DNIC no te lo van a hacer. En ese caso hay que ponerse en contacto con nosotros para cambiar esa cédula por otra.<br /><br />Saludos,<br />GuillermoGuillermo Dotta2017-03-15T18:04:04ZValidación de huella digitalDiego Giussohttps://centroderecursos.agesic.gub.uy/c/message_boards/find_message?p_l_id=33353&messageId=505402017-01-09T15:54:40Z2017-01-09T15:54:40ZEstimados;<br /><br />Estoy viendo la parte de validar la huella digital primero que nada utilizando minucias ya dadas para luego avanzar y ver un caso real integrándolo con algún lector de huellas. Para realizar las pruebas estoy utilizando como base el proyecto de referencia (https://github.com/eIDuy/apdu-services ).<br /> Mirando la clase SmartcardTest veo que hay una serie de minucias, realizando pruebas con esta clase y con el código tal como está en github me surgen algunas consultas:<br /><ul style="list-style: disc outside;"><li> esas minucias corresponden a la cedula de prueba (espécimen)?</li><li> al ejecutar la opción 2 (Card authentication FP) me da una excepción de outofboundsexception, se debe al formato de la minucia utilizada o simplemente error al parsear? El indice que da el error es el de la línea 112 de Utils.java (command[261] = intToByteArray(le)[0];), probé modificar esa línea para solucionar esa excepción pero me dio otros errores de formato al ejecutar (apdu 6A80 por ej).</li></ul> <br />Por último, algo que me paso entre tantas pruebas fue que en un momento se me bloqueo la validación de FP (agote el contador de intentos), intente resetear el contador siguiendo la documentación (IAS Classic Applet V4.pdf, comando Reset Retry Counter) pero no pude, es posible realizar el desbloqueo en caso de que pase eso o cómo funciona?<br /> <br />Gracias y saludos,<br />DiegoDiego Giusso2017-01-09T15:54:40Z