[1.0.0] Upload first version
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -43,3 +43,5 @@ buildNumber.properties
|
|||||||
# JDT-specific (Eclipse Java Development Tools)
|
# JDT-specific (Eclipse Java Development Tools)
|
||||||
.classpath
|
.classpath
|
||||||
|
|
||||||
|
# vscode
|
||||||
|
.vscode/
|
||||||
43
cryptea/pom.xml
Normal file
43
cryptea/pom.xml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>tools.cryptea</groupId>
|
||||||
|
<artifactId>cryptea-tools</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>Cryptea Tools</name>
|
||||||
|
<description>Libreria open source per integrare Cryptea nel tuo workflow. Maggiori dettagli qui https://cryptea.web.francescomancuso.it</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>25</maven.compiler.source>
|
||||||
|
<maven.compiler.target>25</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>tools.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>3.0.3</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.13.0</version>
|
||||||
|
<configuration>
|
||||||
|
<source>${maven.compiler.source}</source>
|
||||||
|
<target>${maven.compiler.target}</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
313
cryptea/src/main/java/tools/cryptea/Certificate.java
Normal file
313
cryptea/src/main/java/tools/cryptea/Certificate.java
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Libreria Cryptea - Gestione dei certificati e verifica
|
||||||
|
*
|
||||||
|
* @author Francesco Mancuso <hello@francescomancuso.it>
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2026-03
|
||||||
|
*
|
||||||
|
* Copyright © 2026 Francesco Mancuso - www.francescomancuso.it
|
||||||
|
* Tutti i diritti riservati.
|
||||||
|
*
|
||||||
|
* Questo software è protetto dalle leggi sul diritto d'autore.
|
||||||
|
*
|
||||||
|
* È vietato l'uso, la copia, la modifica, la distribuzione o
|
||||||
|
* la creazione di opere derivate senza autorizzazione scritta
|
||||||
|
* esplicita dell'autore.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tools.cryptea;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.net.ConnectException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
import java.net.http.HttpResponse.BodyHandlers;
|
||||||
|
import java.net.http.HttpTimeoutException;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
|
||||||
|
import tools.cryptea.utils.Base64Helper;
|
||||||
|
import tools.cryptea.utils.HexHelper;
|
||||||
|
import tools.cryptea.utils.JsonHelper;
|
||||||
|
import tools.jackson.databind.JsonNode;
|
||||||
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
import tools.jackson.databind.node.ObjectNode;
|
||||||
|
|
||||||
|
public class Certificate {
|
||||||
|
|
||||||
|
// Url base per verifica
|
||||||
|
public static final String BASE_URL = "https://cryptea.web.francescomancuso.it";
|
||||||
|
|
||||||
|
// per Jackson v3
|
||||||
|
private static final ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
// per richieste HTTP
|
||||||
|
private static final HttpClient CLIENT = HttpClient.newBuilder()
|
||||||
|
.connectTimeout(Duration.ofSeconds(10))
|
||||||
|
.version(HttpClient.Version.HTTP_1_1)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifica la validità di un certificato offline
|
||||||
|
*
|
||||||
|
* @param content Il certificato in formato CRYPTEA
|
||||||
|
* @return Un array, r[0] indica true/false, r[1] l'eventuale motivo di errore
|
||||||
|
* @throws Exception Nella gestione dei metadata e delle date
|
||||||
|
*/
|
||||||
|
public static String[] verify(String content) throws Exception {
|
||||||
|
String[] ret = new String[2];
|
||||||
|
String publicKey = "-----BEGIN CRYPTEA PUBLIC KEY-----\r\n" + //
|
||||||
|
"AQAB.AMAh44IisBLbYPRAfer5SUp91wCl+9WuLsnRQ56HcXG//OKaMNSfv3mzCBu\r\n" + //
|
||||||
|
"oFgcY3tvVcAqFk6pFrxFq5r0EbG95wEbWP9GuU5y1l07c3dc7Jc2gc2ymCBM+4bL\r\n" + //
|
||||||
|
"Ine70GqRP6cM5XZuab7OGuFHQXWRI28wyo2obiSgCCkAMCFaHsK7vDMbUS9FRQYM\r\n" + //
|
||||||
|
"JS0/Xbp8RyQiSNaPyXUoNjEt9Mvqjqu+dpWuqfHe4myhtjSDLDlNN7oyg8OTfGpC\r\n" + //
|
||||||
|
"Oe4b0G48q5OxZoMEpcohwCkIDep0BtqNt1OJqAY/Md334lKAxlJGCMR0rxp3mD7k\r\n" + //
|
||||||
|
"5h5+fC8pFFjGanHyFsDj+tQDMrBs=\r\n" + //
|
||||||
|
"-----END CRYPTEA PUBLIC KEY-----";
|
||||||
|
String cleaned = content
|
||||||
|
.replace("-----BEGIN CRYPTEA CERTIFICATE-----", "")
|
||||||
|
.replace("-----END CRYPTEA CERTIFICATE-----", "")
|
||||||
|
.replaceAll("\\s", "");
|
||||||
|
cleaned = cleaned.trim();
|
||||||
|
if (cleaned.contains("CRYPTEA") || cleaned.contains("CERTIFICATE")) {
|
||||||
|
throw new IllegalArgumentException("Formato certificato non corretto!");
|
||||||
|
}
|
||||||
|
String[] parts = cleaned.split("\\.");
|
||||||
|
if (parts.length < 4)
|
||||||
|
throw new Exception("Formato certificato incompleto");
|
||||||
|
String metadata = Base64Helper.toString(parts[0]);
|
||||||
|
BigInteger signature = Base64Helper.toBigInteger(parts[3]);
|
||||||
|
|
||||||
|
// 1. Prima di tutto, verifichiamo la firma
|
||||||
|
|
||||||
|
// 1.a Decodifico la firma ottenuta
|
||||||
|
BigInteger[] kPubCA = Keys.publicFromFile("cryptea", publicKey);
|
||||||
|
// kPub[0] = e
|
||||||
|
// kPub[1] = n
|
||||||
|
BigInteger decrypted = RSA.decryptWithPublic(signature, kPubCA[0], kPubCA[1]);
|
||||||
|
|
||||||
|
// 1.b Costruisco il payload
|
||||||
|
String toBeSigned = parts[0] + "." + parts[1] + "." + parts[2];
|
||||||
|
|
||||||
|
// 1.c Calcolo il digest
|
||||||
|
byte[] hash = Digest.getByteDigest(toBeSigned.getBytes());
|
||||||
|
|
||||||
|
// 1.d Confronto digest con quello ottenuto
|
||||||
|
// Forzatura del segno per evitare errori
|
||||||
|
BigInteger calculated = new BigInteger(1, hash);
|
||||||
|
|
||||||
|
if (calculated.equals(decrypted)) {
|
||||||
|
// Firma valida! Controllo i metadata
|
||||||
|
String[] metadataH = metadata.split("\\|");
|
||||||
|
if (metadataH.length < 6) {
|
||||||
|
// Formato metadata incompleto, non valido!
|
||||||
|
throw new Exception("Formato dell'intestazione non valido!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifica rapida sull'owner
|
||||||
|
if (!metadataH[0].contains("owner=")) {
|
||||||
|
// Manca la dichiarazione owner!
|
||||||
|
throw new Exception("Formato dell'intestazione non valido!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!metadataH[1].contains("id=")) {
|
||||||
|
// Manca la dichiarazione id!
|
||||||
|
throw new Exception("Formato dell'intestazione non valido!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifica issuer
|
||||||
|
if (!metadataH[2].equals("issuer=CrypteaCA")) {
|
||||||
|
// Issuer non valido!
|
||||||
|
throw new Exception("Formato dell'intestazione non valido!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifica sulla versione
|
||||||
|
if (!metadataH[3].equals("version=1.0")) {
|
||||||
|
// Versione non valida!
|
||||||
|
throw new Exception("Formato dell'intestazione non valido!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifica sulla data di creazione e scadenza
|
||||||
|
try {
|
||||||
|
// Rimuovo i prefissi prima di fare il parsing delle date
|
||||||
|
String strCreated = metadataH[4].replace("created=", "");
|
||||||
|
String strExpiry = metadataH[5].replace("expiry=", "");
|
||||||
|
|
||||||
|
OffsetDateTime created = OffsetDateTime.parse(strCreated);
|
||||||
|
OffsetDateTime expiry = OffsetDateTime.parse(strExpiry);
|
||||||
|
|
||||||
|
if (created == null || expiry == null) {
|
||||||
|
// Devono essere date valide
|
||||||
|
throw new Exception("Errore nel parsing della data, formato errato!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confronto in UTC
|
||||||
|
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
|
||||||
|
|
||||||
|
if (expiry.isAfter(created) && expiry.isAfter(now)) {
|
||||||
|
// Ok, valido!
|
||||||
|
ret[0] = "true";
|
||||||
|
ret[1] = "";
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
// La data di scadenza deve essere sempre dopo la creazione e "now"
|
||||||
|
ret[0] = "false";
|
||||||
|
ret[1] = "Il certificato è scaduto!";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Errore formato date
|
||||||
|
throw new Exception("Errore nel parsing della data, formato errato!");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Firma non valida, esco...
|
||||||
|
ret[0] = "false";
|
||||||
|
ret[1] = "La firma non è valida. Il contenuto è stato alterato!";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Estrae i metadata (se validi) da un certificato
|
||||||
|
*
|
||||||
|
* @param content Il certificato in formato CRYPTEA
|
||||||
|
* @return I metadati in formato String[]
|
||||||
|
* @throws Exception Se si verificano problemi nel formato
|
||||||
|
*/
|
||||||
|
public static String[] extractMetadata(String content) throws Exception {
|
||||||
|
String cleaned = content
|
||||||
|
.replace("-----BEGIN CRYPTEA CERTIFICATE-----", "")
|
||||||
|
.replace("-----END CRYPTEA CERTIFICATE-----", "")
|
||||||
|
.replaceAll("\\s", "");
|
||||||
|
|
||||||
|
cleaned = cleaned.trim();
|
||||||
|
if (cleaned.contains("CRYPTEA") || cleaned.contains("CERTIFICATE")) {
|
||||||
|
throw new IllegalArgumentException("Formato certificato non corretto!");
|
||||||
|
}
|
||||||
|
String[] parts = cleaned.split("\\.");
|
||||||
|
if (parts.length < 4)
|
||||||
|
throw new Exception("Formato certificato incompleto");
|
||||||
|
return Base64Helper.toString(parts[0]).split("\\|");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Estrae la firma digitale (fingerprint) del certificato
|
||||||
|
* @param content Il certificato in formato CRYPTEA
|
||||||
|
* @return Una stringa, la firma in formato HEX
|
||||||
|
* @throws Exception Nella gestione del formato del certificato
|
||||||
|
*/
|
||||||
|
public static String extractSignature(String content) throws Exception {
|
||||||
|
String cleaned = content
|
||||||
|
.replace("-----BEGIN CRYPTEA CERTIFICATE-----", "")
|
||||||
|
.replace("-----END CRYPTEA CERTIFICATE-----", "")
|
||||||
|
.replaceAll("\\s", "");
|
||||||
|
cleaned = cleaned.trim();
|
||||||
|
if (cleaned.contains("CRYPTEA") || cleaned.contains("CERTIFICATE")) {
|
||||||
|
throw new IllegalArgumentException("Formato certificato non corretto!");
|
||||||
|
}
|
||||||
|
String[] parts = cleaned.split("\\.");
|
||||||
|
if (parts.length < 4)
|
||||||
|
throw new Exception("Formato certificato incompleto");
|
||||||
|
return HexHelper.fromBigInteger(new BigInteger(1, Base64Helper.toBytes(parts[3])));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controlla se il certificato è stato revocato, attraverso una verifica remota
|
||||||
|
* OCSP (Online Certificate Status Protocol)
|
||||||
|
*
|
||||||
|
* @param mdex I metadati estratti dal certificato
|
||||||
|
* @return Un array, r[0] indica true/false, r[1] l'eventuale motivo di errore
|
||||||
|
* @throws Exception Nella gestione della richiesta HTTP
|
||||||
|
*/
|
||||||
|
public static String[] certificateIsActive(String[] metadataExtracted) throws Exception {
|
||||||
|
String[] ret = new String[2];
|
||||||
|
|
||||||
|
ObjectNode json = mapper.createObjectNode();
|
||||||
|
json.put("action", "verify_cert");
|
||||||
|
|
||||||
|
ObjectNode metadata = mapper.createObjectNode();
|
||||||
|
String finalJson = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (String meta : metadataExtracted) {
|
||||||
|
// Split del "="
|
||||||
|
String[] data = meta.split("\\=");
|
||||||
|
metadata.put(data[0], data[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
json.set("metadata", metadata);
|
||||||
|
finalJson = JsonHelper.nodeToJson(json);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new Exception("Formato metadati errato.");
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpRequest request = HttpRequest.newBuilder()
|
||||||
|
.uri(new URI(BASE_URL + "/api/v2/verify"))
|
||||||
|
.headers("Content-Type", "application/json")
|
||||||
|
.timeout(Duration.ofSeconds(15))
|
||||||
|
.POST(HttpRequest.BodyPublishers.ofString(finalJson))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try {
|
||||||
|
HttpResponse<String> response = CLIENT.send(request, BodyHandlers.ofString());
|
||||||
|
|
||||||
|
JsonNode jsonRes = JsonHelper.jsonToNode(response.body());
|
||||||
|
String status = jsonRes.get("status").asString();
|
||||||
|
|
||||||
|
if (status.equals("ok")) {
|
||||||
|
ret[0] = jsonRes.get("isActive").asString();
|
||||||
|
} else {
|
||||||
|
ret[0] = "null";
|
||||||
|
ret[1] = "Errore nel processo di verifica!";
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (HttpTimeoutException e) {
|
||||||
|
throw new HttpTimeoutException("Timeout del server. Potrebbe essere offline?");
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Effettua il ping al server CrypteaCA per verificare lo stato dei servizi
|
||||||
|
* @return TRUE/FALSE
|
||||||
|
* @throws HttpTimeoutException Nella gestione della richiesta
|
||||||
|
*/
|
||||||
|
public static boolean ping() throws HttpTimeoutException {
|
||||||
|
try {
|
||||||
|
HttpRequest request = HttpRequest.newBuilder()
|
||||||
|
.uri(new URI(BASE_URL + "/api/v2/ping"))
|
||||||
|
.headers("Content-Type", "application/json")
|
||||||
|
.timeout(Duration.ofSeconds(15))
|
||||||
|
.GET()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse<String> response = CLIENT.send(request, BodyHandlers.ofString());
|
||||||
|
|
||||||
|
JsonNode jsonRes = JsonHelper.jsonToNode(response.body());
|
||||||
|
String status = jsonRes.get("status").asString();
|
||||||
|
|
||||||
|
if (status.equals("ok")) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (HttpTimeoutException e) {
|
||||||
|
throw new HttpTimeoutException("Timeout del server. Potrebbe essere offline?");
|
||||||
|
} catch (ConnectException e) {
|
||||||
|
return false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new HttpTimeoutException("Errore nel contattare il server. Stato sconosciuto.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
50
cryptea/src/main/java/tools/cryptea/Digest.java
Normal file
50
cryptea/src/main/java/tools/cryptea/Digest.java
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Libreria Cryptea - Calcolo del digest SHA-512
|
||||||
|
*
|
||||||
|
* @author Francesco Mancuso <hello@francescomancuso.it>
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2026-03
|
||||||
|
*
|
||||||
|
* Copyright © 2026 Francesco Mancuso - www.francescomancuso.it
|
||||||
|
* Tutti i diritti riservati.
|
||||||
|
*
|
||||||
|
* Questo software è protetto dalle leggi sul diritto d'autore.
|
||||||
|
*
|
||||||
|
* È vietato l'uso, la copia, la modifica, la distribuzione o
|
||||||
|
* la creazione di opere derivate senza autorizzazione scritta
|
||||||
|
* esplicita dell'autore.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tools.cryptea;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
|
||||||
|
public class Digest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcola il digest generando una stringa HEX
|
||||||
|
* @param bytes Array di byte come input del digest
|
||||||
|
* @return Il digest in formato String HEX
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static String getStringDigest(byte[] bytes) throws Exception {
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("SHA-512");
|
||||||
|
byte[] hash = digest.digest(bytes);
|
||||||
|
String hashtext = new BigInteger(1, hash).toString(16).toUpperCase();
|
||||||
|
return hashtext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcola il digest generando un array di byte[]
|
||||||
|
* @param bytes Array di byte come input del digest
|
||||||
|
* @return Il digest in formato byte[]
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static byte[] getByteDigest(byte[] bytes) throws Exception {
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("SHA-512");
|
||||||
|
byte[] hash = digest.digest(bytes);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
126
cryptea/src/main/java/tools/cryptea/Keys.java
Normal file
126
cryptea/src/main/java/tools/cryptea/Keys.java
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Libreria Cryptea - Gestione delle chiavi nel formato Cryptea
|
||||||
|
*
|
||||||
|
* @author Francesco Mancuso <hello@francescomancuso.it>
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2026-03
|
||||||
|
*
|
||||||
|
* Copyright © 2026 Francesco Mancuso - www.francescomancuso.it
|
||||||
|
* Tutti i diritti riservati.
|
||||||
|
*
|
||||||
|
* Questo software è protetto dalle leggi sul diritto d'autore.
|
||||||
|
*
|
||||||
|
* È vietato l'uso, la copia, la modifica, la distribuzione o
|
||||||
|
* la creazione di opere derivate senza autorizzazione scritta
|
||||||
|
* esplicita dell'autore.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tools.cryptea;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import tools.cryptea.utils.Base64Helper;
|
||||||
|
|
||||||
|
public class Keys {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Funzione Helper per stampare le chiavi su righe da 64 caratteri
|
||||||
|
* @param input Il contenuto del file
|
||||||
|
* @return Il contenuto formattato
|
||||||
|
*/
|
||||||
|
private static String wrapLines(String input) {
|
||||||
|
StringBuilder res = new StringBuilder();
|
||||||
|
char[] array = input.toCharArray();
|
||||||
|
int cont = 0;
|
||||||
|
for (int i = 0; i < input.length(); i++) {
|
||||||
|
res.append(array[i]);
|
||||||
|
cont++;
|
||||||
|
// Arrivo a 64, ma evito l'ultimo char
|
||||||
|
if (cont == 64 && i < input.length() - 1) {
|
||||||
|
res.append("\n");
|
||||||
|
cont = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Genera il contenuto del file che contiene Kpub
|
||||||
|
*
|
||||||
|
* @param n Modulo n di RSA
|
||||||
|
* @param e Esponente pubblico di RSA
|
||||||
|
* @return Ritorna la chiave di tipo String
|
||||||
|
*/
|
||||||
|
public static String publicToFile(BigInteger e, BigInteger n) {
|
||||||
|
String b64E = Base64Helper.fromBigInteger(e);
|
||||||
|
String b64N = Base64Helper.fromBigInteger(n);
|
||||||
|
String crypteaF = b64E + "." + b64N;
|
||||||
|
return "-----BEGIN CRYPTEA PUBLIC KEY-----\n" + wrapLines(crypteaF) + "\n-----END CRYPTEA PUBLIC KEY-----";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legge il contenuto di un file che contiene Kpub
|
||||||
|
*
|
||||||
|
* @param content Il contenuto formattato
|
||||||
|
* @return Ritorna i valori "e" "n" in formato BigInteger[]
|
||||||
|
*/
|
||||||
|
public static BigInteger[] publicFromFile(String type, String content) throws Exception {
|
||||||
|
BigInteger[] kPub = { BigInteger.ZERO, BigInteger.ZERO };
|
||||||
|
String cleaned = content
|
||||||
|
.replace("-----BEGIN CRYPTEA PUBLIC KEY-----", "")
|
||||||
|
.replace("-----END CRYPTEA PUBLIC KEY-----", "")
|
||||||
|
.replaceAll("\\s", "")
|
||||||
|
.trim();
|
||||||
|
if (cleaned.contains("CRYPTEA") || cleaned.contains("KEY")) {
|
||||||
|
throw new IllegalArgumentException("Formato chiave non corretto!");
|
||||||
|
}
|
||||||
|
String[] parts = cleaned.split("\\.");
|
||||||
|
if (parts.length < 2)
|
||||||
|
throw new Exception("Formato chiave non valido");
|
||||||
|
kPub[0] = Base64Helper.toBigInteger(parts[0]); // e
|
||||||
|
kPub[1] = Base64Helper.toBigInteger(parts[1]); // n
|
||||||
|
return kPub;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Genera il contenuto del file che contiene Kpr
|
||||||
|
*
|
||||||
|
* @param k Esponente privato di RSA
|
||||||
|
* @param n Modulo n di RSA
|
||||||
|
* @param p Numero primo p
|
||||||
|
* @param q Numero primo q
|
||||||
|
* @return Ritorna la chiave di tipo String
|
||||||
|
*/
|
||||||
|
public static String privateToFile(BigInteger k, BigInteger n, BigInteger p, BigInteger q) {
|
||||||
|
String b64K = Base64Helper.fromBigInteger(k);
|
||||||
|
String b64N = Base64Helper.fromBigInteger(n);
|
||||||
|
String b64P = Base64Helper.fromBigInteger(p);
|
||||||
|
String b64Q = Base64Helper.fromBigInteger(q);
|
||||||
|
String crypteaF = b64K + "." + b64N + "." + b64P + "." + b64Q;
|
||||||
|
return "-----BEGIN CRYPTEA PRIVATE KEY-----\n" + wrapLines(crypteaF) + "\n-----END CRYPTEA PRIVATE KEY-----";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legge il contenuto di un file che contiene Kpr
|
||||||
|
*
|
||||||
|
* @param content Il contenuto formattato
|
||||||
|
* @return Ritorna i valori "k" "n" in formato BigInteger[]
|
||||||
|
*/
|
||||||
|
public static BigInteger[] privateFromFile(String content) throws Exception {
|
||||||
|
BigInteger[] kPr = { BigInteger.ZERO, BigInteger.ZERO };
|
||||||
|
String cleaned = content
|
||||||
|
.replace("-----BEGIN CRYPTEA PRIVATE KEY-----", "")
|
||||||
|
.replace("-----END CRYPTEA PRIVATE KEY-----", "")
|
||||||
|
.replaceAll("\\s", "")
|
||||||
|
.trim();
|
||||||
|
if (cleaned.contains("CRYPTEA") || cleaned.contains("KEY")) {
|
||||||
|
throw new IllegalArgumentException("Formato chiave non corretto!");
|
||||||
|
}
|
||||||
|
String[] parts = cleaned.split("\\.");
|
||||||
|
if (parts.length < 4)
|
||||||
|
throw new Exception("Formato chiave privata incompleto");
|
||||||
|
kPr[0] = Base64Helper.toBigInteger(parts[0]);
|
||||||
|
kPr[1] = Base64Helper.toBigInteger(parts[1]);
|
||||||
|
return kPr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
100
cryptea/src/main/java/tools/cryptea/RSA.java
Normal file
100
cryptea/src/main/java/tools/cryptea/RSA.java
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Libreria Cryptea - Operazioni RSA cifratura / decifratura
|
||||||
|
*
|
||||||
|
* @author Francesco Mancuso <hello@francescomancuso.it>
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2026-03
|
||||||
|
*
|
||||||
|
* Copyright © 2026 Francesco Mancuso - www.francescomancuso.it
|
||||||
|
* Tutti i diritti riservati.
|
||||||
|
*
|
||||||
|
* Questo software è protetto dalle leggi sul diritto d'autore.
|
||||||
|
*
|
||||||
|
* È vietato l'uso, la copia, la modifica, la distribuzione o
|
||||||
|
* la creazione di opere derivate senza autorizzazione scritta
|
||||||
|
* esplicita dell'autore.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tools.cryptea;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import tools.cryptea.utils.EspMod;
|
||||||
|
|
||||||
|
public class RSA {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cifra il contenuto con la chiave pubblica
|
||||||
|
* @param input in formato BigInt
|
||||||
|
* @param e Esponente pubblico RSA
|
||||||
|
* @param n Modulo RSA
|
||||||
|
* @return Risultato dell'operazione
|
||||||
|
*/
|
||||||
|
public static BigInteger encryptWithPublic(BigInteger input, BigInteger e, BigInteger n) {
|
||||||
|
BigInteger output = BigInteger.ZERO;
|
||||||
|
|
||||||
|
if (n != null && e != null) {
|
||||||
|
output = EspMod.doIt(input, e, n);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Parametri chiave pubblica incompleti o non validi.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cifra il contenuto con la chiave privata
|
||||||
|
* @param input in formato BigInt
|
||||||
|
* @param k Esponente privato RSA
|
||||||
|
* @param n Modulo RSA
|
||||||
|
* @return Risultato dell'operazione
|
||||||
|
*/
|
||||||
|
public static BigInteger encryptWithPrivate(BigInteger input, BigInteger k, BigInteger n) {
|
||||||
|
BigInteger output = BigInteger.ZERO;
|
||||||
|
|
||||||
|
if (n != null && k != null) {
|
||||||
|
output = EspMod.doIt(input, k, n);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Parametri chiave privata incompleti o non validi.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decifra il contenuto con la chiave privata
|
||||||
|
* @param input in formato BigInt
|
||||||
|
* @param k Esponente privato RSA
|
||||||
|
* @param n Modulo RSA
|
||||||
|
* @return Risultato dell'operazione
|
||||||
|
*/
|
||||||
|
public static BigInteger decryptWithPrivate(BigInteger input, BigInteger k, BigInteger n) {
|
||||||
|
BigInteger output = BigInteger.ZERO;
|
||||||
|
|
||||||
|
if (n != null && k != null) {
|
||||||
|
output = EspMod.doIt(input, k, n);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Parametri chiave privata incompleti o non validi.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decifra il contenuto con la chiave pubblica
|
||||||
|
* @param input in formato BigInt
|
||||||
|
* @param e Esponente pubblico RSA
|
||||||
|
* @param n Modulo RSA
|
||||||
|
* @return Risultato dell'operazione
|
||||||
|
*/
|
||||||
|
public static BigInteger decryptWithPublic(BigInteger input, BigInteger e, BigInteger n) {
|
||||||
|
BigInteger output = BigInteger.ZERO;
|
||||||
|
|
||||||
|
if (n != null && e != null) {
|
||||||
|
output = EspMod.doIt(input, e, n);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Parametri chiave pubblica incompleti o non validi.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
92
cryptea/src/main/java/tools/cryptea/utils/Base64Helper.java
Normal file
92
cryptea/src/main/java/tools/cryptea/utils/Base64Helper.java
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Libreria Cryptea - Strumenti di conversione Base64
|
||||||
|
*
|
||||||
|
* @author Francesco Mancuso <hello@francescomancuso.it>
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2026-03
|
||||||
|
*
|
||||||
|
* Copyright © 2026 Francesco Mancuso - www.francescomancuso.it
|
||||||
|
* Tutti i diritti riservati.
|
||||||
|
*
|
||||||
|
* Questo software è protetto dalle leggi sul diritto d'autore.
|
||||||
|
*
|
||||||
|
* È vietato l'uso, la copia, la modifica, la distribuzione o
|
||||||
|
* la creazione di opere derivate senza autorizzazione scritta
|
||||||
|
* esplicita dell'autore.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tools.cryptea.utils;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
public class Base64Helper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trasforma un numero BigInteger in una stringa Base64
|
||||||
|
*
|
||||||
|
* @param n
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String fromBigInteger(BigInteger n) {
|
||||||
|
return Base64.getEncoder().encodeToString(n.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trasforma una stringa Base64 in un numero BigInteger
|
||||||
|
*
|
||||||
|
* @param base64
|
||||||
|
* @return BigInteger
|
||||||
|
*/
|
||||||
|
public static BigInteger toBigInteger(String base64) {
|
||||||
|
// da base64 salvo i bytes
|
||||||
|
byte[] bytes = Base64.getDecoder().decode(base64);
|
||||||
|
|
||||||
|
// uso 1 per forzare il segno positivo ed evitare errori
|
||||||
|
return new BigInteger(1, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trasforma un array di bytes in una stringa Base64
|
||||||
|
*
|
||||||
|
* @param bytes
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String fromBytes(byte[] bytes) {
|
||||||
|
return Base64.getEncoder().encodeToString(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trasforma una stringa Base64 in un array di bytes
|
||||||
|
*
|
||||||
|
* @param base64
|
||||||
|
* @return byte[]
|
||||||
|
*/
|
||||||
|
public static byte[] toBytes(String base64) {
|
||||||
|
// da base64 salvo i bytes
|
||||||
|
byte[] bytes = Base64.getDecoder().decode(base64);
|
||||||
|
|
||||||
|
// uso 1 per forzare il segno positivo ed evitare errori
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trasforma un oggetto String in stringa Base64
|
||||||
|
* @param content
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String fromString(String content) {
|
||||||
|
return fromBytes(content.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trasforma una stringa Base64 in un oggetto String
|
||||||
|
* @param content
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String toString(String content) {
|
||||||
|
return new String(Base64.getDecoder().decode(content), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
55
cryptea/src/main/java/tools/cryptea/utils/EspMod.java
Normal file
55
cryptea/src/main/java/tools/cryptea/utils/EspMod.java
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Libreria Cryptea - Algoritmo di Esponenziazione Modulare
|
||||||
|
*
|
||||||
|
* @author Francesco Mancuso <hello@francescomancuso.it>
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2026-03
|
||||||
|
*
|
||||||
|
* Copyright © 2026 Francesco Mancuso - www.francescomancuso.it
|
||||||
|
* Tutti i diritti riservati.
|
||||||
|
*
|
||||||
|
* Questo software è protetto dalle leggi sul diritto d'autore.
|
||||||
|
*
|
||||||
|
* È vietato l'uso, la copia, la modifica, la distribuzione o
|
||||||
|
* la creazione di opere derivate senza autorizzazione scritta
|
||||||
|
* esplicita dell'autore.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tools.cryptea.utils;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
public class EspMod {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Algoritmo di Esponenziazione Modulare per velocizzare i calcoli RSA.
|
||||||
|
* Maggiori dettagli nella nostra documentazione https://cryptea.web.francescomancuso.it
|
||||||
|
* @param a Base della potenza
|
||||||
|
* @param b Esponente della potenza
|
||||||
|
* @param n Numero mod n
|
||||||
|
* @return Risultato operazione
|
||||||
|
*/
|
||||||
|
public static BigInteger doIt(BigInteger a, BigInteger b, BigInteger n) {
|
||||||
|
BigInteger result = BigInteger.valueOf(1);
|
||||||
|
|
||||||
|
// 1. Calcolo il primo modulo della produttoria
|
||||||
|
a = a.mod(n);
|
||||||
|
|
||||||
|
// 2. Avvio il ciclo while per effettuare tutti i prodotti
|
||||||
|
// mentre b > 0 (true = 1)
|
||||||
|
while (b.compareTo(BigInteger.ZERO) == 1) {
|
||||||
|
if (b.getLowestSetBit() == 0) {
|
||||||
|
// se è dispari (ultimo bit uguale a 1)
|
||||||
|
result = (result.multiply(a)).mod(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Calcolo la successiva potenza
|
||||||
|
a = (a.multiply(a)).mod(n);
|
||||||
|
|
||||||
|
// 4. Divido per 2 b
|
||||||
|
b = b.shiftRight(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
cryptea/src/main/java/tools/cryptea/utils/HexHelper.java
Normal file
42
cryptea/src/main/java/tools/cryptea/utils/HexHelper.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Libreria Cryptea - Strumenti di conversione HEX
|
||||||
|
*
|
||||||
|
* @author Francesco Mancuso <hello@francescomancuso.it>
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2026-03
|
||||||
|
*
|
||||||
|
* Copyright © 2026 Francesco Mancuso - www.francescomancuso.it
|
||||||
|
* Tutti i diritti riservati.
|
||||||
|
*
|
||||||
|
* Questo software è protetto dalle leggi sul diritto d'autore.
|
||||||
|
*
|
||||||
|
* È vietato l'uso, la copia, la modifica, la distribuzione o
|
||||||
|
* la creazione di opere derivate senza autorizzazione scritta
|
||||||
|
* esplicita dell'autore.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tools.cryptea.utils;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
public class HexHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trasforma un numero BigInteger in una stringa Hex
|
||||||
|
* @param n
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static String fromBigInteger(BigInteger n) {
|
||||||
|
return n.toString(16).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trasforma una stringa Hex in un numero BigInteger
|
||||||
|
* @param hex
|
||||||
|
* @return BigInteger
|
||||||
|
*/
|
||||||
|
public static BigInteger toBigInteger(String hex) {
|
||||||
|
return new BigInteger(hex, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
76
cryptea/src/main/java/tools/cryptea/utils/JsonHelper.java
Normal file
76
cryptea/src/main/java/tools/cryptea/utils/JsonHelper.java
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Libreria Cryptea - Strumenti di lavoro per JSON
|
||||||
|
*
|
||||||
|
* @author Francesco Mancuso <hello@francescomancuso.it>
|
||||||
|
* @version 1.0
|
||||||
|
* @since 2026-03
|
||||||
|
*
|
||||||
|
* Copyright © 2026 Francesco Mancuso - www.francescomancuso.it
|
||||||
|
* Tutti i diritti riservati.
|
||||||
|
*
|
||||||
|
* Questo software è protetto dalle leggi sul diritto d'autore.
|
||||||
|
*
|
||||||
|
* È vietato l'uso, la copia, la modifica, la distribuzione o
|
||||||
|
* la creazione di opere derivate senza autorizzazione scritta
|
||||||
|
* esplicita dell'autore.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package tools.cryptea.utils;
|
||||||
|
|
||||||
|
import tools.jackson.databind.JsonNode;
|
||||||
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
import tools.jackson.databind.node.ObjectNode;
|
||||||
|
|
||||||
|
public class JsonHelper {
|
||||||
|
|
||||||
|
// per Jackson v3
|
||||||
|
private static final ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converte un Oggetto generico in formato JSON
|
||||||
|
* @param obj Oggetto generico da convertire
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String objectToJson(Object obj) {
|
||||||
|
try {
|
||||||
|
return mapper.writeValueAsString(obj);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Errore durante la serializzazione JSON", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Estrare un oggetto di tipo T da una stringa JSON
|
||||||
|
* @param <T> Il tipo dell'oggetto da estrarre
|
||||||
|
* @param json Stringa JSON
|
||||||
|
* @param clazz La classe che rappresenta la struttura dell'oggetto
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> T objectFromJson(String json, Class<T> clazz) {
|
||||||
|
try {
|
||||||
|
return mapper.readValue(json, clazz);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Errore durante la deserializzazione JSON", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converte un ObjectNode di Jackson in stringa JSON
|
||||||
|
* @param jsonNode Il nodo di partenza
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String nodeToJson(ObjectNode jsonNode) {
|
||||||
|
String result = mapper.writeValueAsString(jsonNode);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converte una stringa JSON in un ObjectNode di Jackson
|
||||||
|
* @param json La stringa JSON
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static JsonNode jsonToNode(String json) {
|
||||||
|
return mapper.readTree(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user