Signieren und Validieren mit java.security.Provider

Hinweise zur Verwendung von java.security.Provider

In java.security gibt es einen Mechanismus namens Provider, mit dem Sie Verschlüsselungs- und Signaturimplementierungen hinzufügen können. Wahrscheinlich wird er jedoch nur von wenigen Personen verwendet, sodass es nicht viele Websites gibt, die dies erklären.

Versuchen Sie zunächst, mit Java zu signieren und zu überprüfen

Sample.java


package io.github.tshibata.sample;

import java.security.*;

public class Sample {
	static void test(byte[] data, KeyPair pair) throws Exception {
		Signature sig = Signature.getInstance("SHA256withRSA");
		//Ich werde unterschreiben
		sig.initSign(pair.getPrivate());
		sig.update(data);
		byte[] s = sig.sign();
		//Ich werde es mit Base 64 ausgeben
		System.out.println(java.util.Base64.getEncoder().encodeToString​(s));
		//Ich werde überprüfen
		sig.initVerify(pair.getPublic());
		sig.update(data);
		System.out.println(sig.verify(s));
	}
	public static void main(String[] args) throws Exception {
		//Ich werde einen Schlüssel machen
		KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
		KeyPair pair = gen.generateKeyPair();
		// "hello"Ich werde unterschreiben und überprüfen
		test("hello".getBytes(), pair);
	}
}

Versuchen Sie, eine Unterklasse von Signature zu implementieren

Die Signaturklasse ist für die Signatur zuständig.

MySignature.java


package io.github.tshibata.sample;

import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;

import java.math.BigInteger;

public class MySignature extends Signature {

// echo | openssl dgst -sign private.pem | openssl rsautl -verify -inkey private.pem -raw | head --bytes=-32 | base64

	private static byte[] padding = java.util.Base64.getDecoder().decode(
		"AAH/////////////////////////////////////////////////////////////////////////" +
		"////////////////////////////////////////////////////////////////////////////" +
		"////////////////////////////////////////////////////////////////////////////" +
		"////////////////////////////////////////////ADAxMA0GCWCGSAFlAwQCAQUABCA=");

	private RSAPrivateKey privateKey;

	private RSAPublicKey publicKey;

	private MessageDigest messageDigest;

	public MySignature() {
		super("SHA256withRSA");
		try {
			messageDigest = MessageDigest.getInstance("SHA-256");
		} catch (NoSuchAlgorithmException exc) {
			throw new UnsupportedOperationException(exc);
		}
	}

	protected Object engineGetParameter(String param) throws InvalidParameterException {
		throw new UnsupportedOperationException("engineGetParameter");
	}

	protected void engineSetParameter(String param, Object value) throws InvalidParameterException {
		throw new UnsupportedOperationException("engineSetParameter");
	}

	protected void engineInitSign(PrivateKey key) throws InvalidKeyException {
		messageDigest.reset();
		privateKey = (RSAPrivateKey) key;
	}

	protected void engineInitVerify(PublicKey key) throws InvalidKeyException {
		messageDigest.reset();
		publicKey = (RSAPublicKey) key;
	}

	protected void engineUpdate(byte[] data, int offset, int length) throws SignatureException {
		messageDigest.update(data, offset, length);
	}

	protected void engineUpdate(byte data) throws SignatureException {
		messageDigest.update(data);
	}

	protected byte[] engineSign() throws SignatureException {
		byte[] data = new byte[256];
		System.arraycopy(padding, 0, data, 0, padding.length);
		byte[] digest = messageDigest.digest();
		System.arraycopy(digest, 0, data, padding.length, digest.length);
		BigInteger m = new BigInteger(1, data);
		BigInteger d = privateKey.getPrivateExponent();
		BigInteger n = privateKey.getModulus();
		BigInteger c = m.modPow(d, n);

		byte[] signed = new byte[256];
		for (int i = signed.length - 1; 0 <= i; i--) {
			signed[i] = c.byteValue();
			c = c.shiftRight(8);
		}
		return signed;
	}

	protected boolean engineVerify(byte[] signed) throws SignatureException {
		BigInteger c = new BigInteger(1, signed);
		BigInteger e = publicKey.getPublicExponent();
		BigInteger n = publicKey.getModulus();
		BigInteger m = c.modPow(e, n);

		byte[] data = new byte[256];
		System.arraycopy(padding, 0, data, 0, padding.length);
		byte[] digest = messageDigest.digest();
		System.arraycopy(digest, 0, data, padding.length, digest.length);
		for (int i = data.length - 1; 0 <= i; i--) {
			if (data[i] != m.byteValue()) {
				return false;
			}
			m = m.shiftRight(8);
		}
		return true;
	}
}

Die Schlüssellänge ist auf 2048 Bit (256 Byte) festgelegt. Alles, was Sie tun müssen, ist, einen Hash zu erstellen, ihn aufzufüllen, mit dem Exponenten zu multiplizieren und durch den Modul zu dividieren, um den Rest zu berechnen. Polsterung ist eine Magie oder eine Regel.

echo | openssl dgst -sign private.pem | openssl rsautl -verify -inkey private.pem -raw | head --bytes=-32 | base64

Ich habe es gemacht. "Der Rest des Reit-Exponenten und der Division durch den Modul" ist der Schlüssel zu RSA und wurde in der Vergangenheit von großen Gelehrten gefunden. Um dies in zu verwenden

MyProvider.java


package io.github.tshibata.sample;

import java.security.*;

public class MyProvider extends Provider {

	public MyProvider() {
		super("MyProvider", "1.0", "My provider");
		put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.11", "SHA256withRSA");
		put("Signature.SHA256withRSA SupportedKeyClasses", "java.security.interfaces.RSAPublicKey|java.security.interfaces.RSAPrivateKey");
		put("Signature.SHA256withRSA", "io.github.tshibata.sample.MySignature");
		put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA");
	}
}

Erstellen Sie eine Unterklasse von Provider mit dem Namen

Sample.java


package io.github.tshibata.sample;

import java.security.*;

public class Sample {
	static void test(byte[] data, KeyPair pair) throws Exception {
		Signature sig = Signature.getInstance("SHA256withRSA");
		//Ich werde unterschreiben
		sig.initSign(pair.getPrivate());
		sig.update(data);
		byte[] s = sig.sign();
		//Ich werde es mit Base 64 ausgeben
		System.out.println(java.util.Base64.getEncoder().encodeToString​(s));
		//Ich werde überprüfen
		sig.initVerify(pair.getPublic());
		sig.update(data);
		System.out.println(sig.verify(s));
	}
	public static void main(String[] args) throws Exception {
		//Ich werde einen Schlüssel machen
		KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
		KeyPair pair = gen.generateKeyPair();
		// "hello"Ich werde unterschreiben und überprüfen
		test("hello".getBytes(), pair);
		//Ich werde versuchen, MyProvider zu verwenden
		Security.insertProviderAt(new MyProvider(), 1);
		test("hello".getBytes(), pair);
	}
}

Ich werde es vor der Unterzeichnung und Überprüfung registrieren. Wenn das zweite Argument von insertProviderAt in der Priorität auf 1 gesetzt ist, wird es mit der höchsten Priorität verwendet.

Recommended Posts

Signieren und Validieren mit java.security.Provider
Federvalidierung und Fehlercode
Animation mit MatchedGeometryEffect und @Namespace
Passwort-Hashing und Authentifizierung mit JBcrypt
Validierung von Protokollnachrichten mit mockito
[Rails] Validierungseinstellungen und japanische Lokalisierung
Implementierung der Validierung mit regulären Ausdrücken
Infrastrukturüberwachung mit Graphite und StatsD