Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

229
Views
Firma ciega Chaum con cegamiento en JavaScript y verificación en Java

Estoy experimentando con la firma ciega de Chaum, y lo que estoy tratando de hacer es cegar y descifrar en JavaScript, y firmar y verificar en Java (con castillo hinchable). Para el lado de Java, mi fuente es this , y para JavaScript, encontré firmas ciegas . He creado dos pequeños códigos para jugar, para el lado de Java:

 package crypto; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.engines.RSAEngine; import org.bouncycastle.crypto.generators.RSAKeyPairGenerator; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.RSAKeyGenerationParameters; import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.signers.PSSSigner; import org.bouncycastle.crypto.util.PrivateKeyInfoFactory; import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory; import org.bouncycastle.openssl.jcajce.JcaPEMWriter; import org.bouncycastle.util.io.pem.PemObject; import java.io.IOException; import java.io.StringWriter; import java.math.BigInteger; import java.security.SecureRandom; import java.util.Base64; import java.util.Scanner; public class RsaConcealedMessageTest { public static void main(String[] args) { AsymmetricCipherKeyPair rsaKeyPair = generateKeyPair(); Scanner userInput = new Scanner(System.in); try { printKeyPairPems(rsaKeyPair); // Producing signature on concealed message System.out.print("Concealed message (in base64)?"); String concealedMessageBase64 = userInput.nextLine(); byte[] concealedMessageBytes = Base64.getDecoder().decode(concealedMessageBase64); byte[] signatureOnConcealedMessage = signConcealedMessage(concealedMessageBytes, rsaKeyPair.getPrivate()); System.out.println("Signature on concealed message (base64): " + Base64.getEncoder().encodeToString(signatureOnConcealedMessage)); // Verifying revealed signature on revealed message System.out.print("Revealed message (in base64)?"); String revealedMessageBase64 = userInput.nextLine(); System.out.print("Revealed signature (in base64)?"); String revealedSignatureBase64 = userInput.nextLine(); byte[] revealedMessageBytes = Base64.getDecoder().decode(revealedMessageBase64); System.out.println("Revealed message is: " + new String(revealedMessageBytes)); byte[] revealedSignatureBytes = Base64.getDecoder().decode(revealedSignatureBase64); PSSSigner signer = new PSSSigner(new RSAEngine(), new SHA256Digest(), 0); signer.init(false, rsaKeyPair.getPublic()); signer.update(revealedMessageBytes, 0, revealedMessageBytes.length); boolean isVerified = signer.verifySignature(revealedSignatureBytes); System.out.println("Revealed signature is verified on revealed message: " + isVerified); } catch (IOException e) { e.printStackTrace(); } } private static AsymmetricCipherKeyPair generateKeyPair() { RSAKeyPairGenerator generator = new RSAKeyPairGenerator(); BigInteger publicExponent = new BigInteger("10001", 16); SecureRandom random = new SecureRandom(); RSAKeyGenerationParameters keyGenParams = new RSAKeyGenerationParameters( publicExponent, random, 4096, 80 ); generator.init(keyGenParams); return generator.generateKeyPair(); } private static void printKeyPairPems(AsymmetricCipherKeyPair keyPair) throws IOException { RSAKeyParameters publicKey = (RSAKeyParameters) keyPair.getPublic(); byte[] publicKeyBytes = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey).getEncoded(); printKeyPem("PUBLIC KEY", publicKeyBytes); RSAKeyParameters privateKey = (RSAKeyParameters) keyPair.getPrivate(); byte[] privateKeyBytes = PrivateKeyInfoFactory.createPrivateKeyInfo(privateKey).getEncoded(); printKeyPem("PRIVATE KEY", privateKeyBytes); } private static void printKeyPem(String keyType, byte[] keyBytes) throws IOException { PemObject pemObject = new PemObject(keyType, keyBytes); StringWriter keyStringWriter = new StringWriter(); JcaPEMWriter pemWriter = new JcaPEMWriter(keyStringWriter); pemWriter.writeObject(pemObject); pemWriter.close(); System.out.println(keyType + ": " + keyStringWriter.toString().replace("\n", "")); } private static byte[] signConcealedMessage(byte[] concealedMessage, AsymmetricKeyParameter privateKey) { RSAEngine engine = new RSAEngine(); engine.init(true, privateKey); return engine.processBlock(concealedMessage, 0, concealedMessage.length); } }

Lo anterior generará un par de claves, imprimirá la parte pública en la salida estándar y leerá desde la entrada estándar el mensaje oculto y luego el mensaje no oculto y la firma. Y para el lado de JavaScript (Node.js), tengo esto:

 const BigInteger = require('jsbn').BigInteger; const BlindSignature = require('blind-signatures'); const NodeRSA = require('node-rsa'); const prompt = require('prompt-sync')(); const publicKeyInput = prompt("Public key in PEM?"); const publicKey = new NodeRSA(publicKeyInput); // Concealing message const message = "The quick brown fox jumps over the lazy dog! Hello World!"; const concealingResult = BlindSignature.blind( { message: message, N: publicKey.keyPair.n.toString(), E: publicKey.keyPair.e.toString(), } ); const blindedHexStr = concealingResult.blinded.toString(16); const blindedBuffer = Buffer.from(blindedHexStr, 'hex'); console.log(`\nConcealed message (base64): ${blindedBuffer.toString('base64')}`); console.log(`\nr: ${concealingResult.r.toString(16)}`); // Getting signature on concealed message and producing revealed signature const signatureOnConcealedMessageBase64 = prompt("Signature on concealed message (base64)?"); const signatureOnConcealedMessageBuffer = Buffer.from(signatureOnConcealedMessageBase64, 'base64'); const signatureOnConcealedMessageHex = signatureOnConcealedMessageBuffer.toString('hex'); const signatureOnConcealedMessage = new BigInteger(signatureOnConcealedMessageHex, 16) const signatureOnRevealedMessage = BlindSignature.unblind({ signed: signatureOnConcealedMessage, N: publicKey.keyPair.n.toString(), r: concealingResult.r, }); const revealedMessageBuffer = Buffer.from(message, 'utf8'); const revealedMessageBase64 = revealedMessageBuffer.toString('base64'); console.log(`\nRevealed message (base64): ${revealedMessageBase64}`); const signatureOnRevealedMessageHex = signatureOnRevealedMessage.toString(16); const signatureOnRevealedMessageBuffer = Buffer.from(signatureOnRevealedMessageHex, 'hex'); const signatureOnRevealedMessageBase64 = signatureOnRevealedMessageBuffer.toString('base64'); console.log(`\nSignature on revealed message (base64): ${signatureOnRevealedMessageBase64}`);

Esto lee la clave pública, genera el mensaje oculto y lo descifra.

La parte de verificación del código Java falla y realmente no sé por qué. ¿Alguien tiene alguna idea?

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

La biblioteca de firma ciega utilizada en el código NodeJS para la firma ciega implementa el proceso que se describe aquí :

  • BlindSignature.blind() genera el hash SHA256 del mensaje y determina el mensaje ciego m' = m * r e mod N.
  • BlindSignature.sign() calcula la firma ciega s' = (m') d mod N.
  • BlindSignature.unblind() determina la firma no ciega s = s' * r -1 mod N.
  • BlindSignature.verify() descifra la firma no ciega (s e ) y compara el resultado con el mensaje cifrado. Si ambos son iguales, la verificación es exitosa.

No se produce relleno en este proceso.

En el código Java, la implementación de firmar el mensaje oculto en signConcealedMessage() es funcionalmente idéntica a BlindSignature.sign() .
Por el contrario, la verificación en el código Java es incompatible con el proceso anterior porque el código Java usa PSS como relleno durante la verificación.
Un código Java compatible sería, por ejemplo:

 RSAEngine engine = new RSAEngine(); engine.init(false, rsaKeyPair.getPublic()); byte[] signatureDecrypted = engine.processBlock(revealedSignatureBytes, 0, revealedSignatureBytes.length); // calculates s^e byte[] messageHashed = MessageDigest.getInstance("SHA-256").digest(revealedMessageBytes); System.out.println(Arrays.equals(messageHashed, signatureDecrypted)); // verification successfull, if s^e identical with the SHA256 hash of the message

Con este código la verificación es exitosa.


Parece que hay un RFC en trámite para la firma ciega, que de hecho usa una extensión de PSS, consulte draft-irtf-cfrg-rsa-blind-signatures .
BouncyCastle también proporciona una implementación para la firma ciega, consulte, por ejemplo, RSABlindingEngine , que se aplica mediante la biblioteca de Java a la que se hace referencia .

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!