Improved Cryptography section and included samples in Java, C, PHP And Python
This commit is contained in:
parent
6c5ae90b1f
commit
144044a551
5 changed files with 407 additions and 22 deletions
70
README.md
70
README.md
|
@ -69,14 +69,16 @@ This project is licensed under GNU Free Documentation License v1.3, see the [LIC
|
||||||
* [Signing and Signature Verification](#signing-and-signature-verification)
|
* [Signing and Signature Verification](#signing-and-signature-verification)
|
||||||
* [Temporary Signature & Verification](#temporary-signature--verification)
|
* [Temporary Signature & Verification](#temporary-signature--verification)
|
||||||
* [Encryption and Decryption](#encryption-and-decryption)
|
* [Encryption and Decryption](#encryption-and-decryption)
|
||||||
|
* [Error Handling](#error-handling)
|
||||||
* [Methods](#methods)
|
* [Methods](#methods)
|
||||||
* [generateKeyPair()](#generatekeypair)
|
* [generateKeyPair()](#generatekeypair)
|
||||||
* [signContent(content: String, privateKey: String): String](#signcontentcontent-string-privatekey-string-string)
|
* [signContent(content: String, privateKey: String): String](#signcontentcontent-string-privatekey-string-string)
|
||||||
* [verifyContent(content: String, signature: String, publicKey: String): Boolean](#verifycontentcontent-string-signature-string-publickey-string-boolean)
|
* [verifyContent(content: String, signature: String, publicKey: String): Boolean](#verifycontentcontent-string-signature-string-publickey-string-boolean)
|
||||||
* [temporarySignContent(content: String, privateKey: String): String](#temporarysigncontentcontent-string-privatekey-string-string)
|
* [temporarySignContent(content: String, privateKey: String): String](#temporarysigncontentcontent-string-privatekey-string-string)
|
||||||
* [verifyTemporarySignature(content: String, signature: String, publicKey: String, frames: Integer): Boolean](#verifytemporarysignaturecontent-string-signature-string-publickey-string-frames-integer-boolean)
|
* [verifyTemporarySignature(content: String, signature: String, publicKey: String, frames: Integer): Boolean](#verifytemporarysignaturecontent-string-signature-string-publickey-string-frames-integer-boolean)
|
||||||
* [encryptContent(content: String, publicKey: String): String](#encryptcontentcontent-string-publickey-string-string)
|
* [encryptContent(content: String, publicKey: String): String](#encryptcontentcontent-string-publickey-string-string)
|
||||||
* [decryptContent(ciphertext: String, privateKey: String): String](#decryptcontentciphertext-string-privatekey-string-string)
|
* [decryptContent(ciphertext: String, privateKey: String): String](#decryptcontentciphertext-string-privatekey-string-string)
|
||||||
|
* [Example Implementations](#example-implementations)
|
||||||
* [Authentication](#authentication)
|
* [Authentication](#authentication)
|
||||||
* [First-Level Authentication](#first-level-authentication)
|
* [First-Level Authentication](#first-level-authentication)
|
||||||
* [Password (LOGIN)](#password-login)
|
* [Password (LOGIN)](#password-login)
|
||||||
|
@ -350,21 +352,24 @@ The fields in the error response object are as follows:
|
||||||
|
|
||||||
## Cryptography
|
## Cryptography
|
||||||
|
|
||||||
Cryptography is a crucial part of the Socialbox standard, it serves many purposes such as session integrity to prevent
|
Cryptography is a crucial part of the Socialbox standard. It serves many purposes such as session integrity to prevent
|
||||||
session hijacking, data integrity to prevent data tampering, and confidentiality to prevent data eavesdropping. To keep
|
session hijacking, data integrity to prevent data tampering, and confidentiality to prevent data eavesdropping. Every
|
||||||
things simple, every Socialbox client & server must implement the same cryptographic methods to ensure compatibility
|
Socialbox client & server must implement the same cryptographic methods to ensure compatibility with other systems.
|
||||||
with other systems. Mainly, the Socialbox standard uses the following cryptographic methods:
|
Mainly, the Socialbox standard uses the following cryptographic methods:
|
||||||
|
|
||||||
* **RSA**: Used for asymmetric encryption and decryption.
|
* **RSA**: Used for asymmetric encryption and decryption.
|
||||||
* **SHA256**: Used for hashing data and generating secure signatures.
|
* **SHA256**: Used for hashing data and generating secure signatures.
|
||||||
* **Base64 Encoding**: All binary data (such as keys, signatures, and encrypted data) is encoded into Base64 for safe transmission.
|
* **Base64 Encoding**: All binary data (such as keys, signatures, and encrypted data) is encoded into Base64 for safe transmission.
|
||||||
|
|
||||||
|
> Note: Base64 encoding is necessary because binary data cannot be safely transmitted in certain contexts like URLs or
|
||||||
|
JSON. Base64 converts binary data into a text-safe format.
|
||||||
|
|
||||||
### Key Generation
|
### Key Generation
|
||||||
|
|
||||||
Key generation is the process of generating cryptographic keys for encryption and decryption. In Socialbox, RSA keys
|
Key generation is the process of generating cryptographic keys for encryption and decryption. In Socialbox, RSA keys are
|
||||||
are used for asymmetric encryption and decryption. The key generation process involves generating a public key and a
|
used for asymmetric encryption and decryption. The key generation process involves generating a public key and a private
|
||||||
private key. The public key can be shared with others to encrypt/verify data, while the private key is kept secret and
|
key. The public key can be shared with others to encrypt/verify data, while the private key is kept secret and used to
|
||||||
used to decrypt/sign data. These are the following conditions for key generation:
|
decrypt/sign data. These are the following conditions for key generation:
|
||||||
|
|
||||||
* **Key Size**: The key size must be 2048 bits.
|
* **Key Size**: The key size must be 2048 bits.
|
||||||
* **Algorithm**: The algorithm used for key generation must be RSA.
|
* **Algorithm**: The algorithm used for key generation must be RSA.
|
||||||
|
@ -399,10 +404,9 @@ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQ...
|
||||||
|
|
||||||
### Signing and Signature Verification
|
### Signing and Signature Verification
|
||||||
|
|
||||||
Signing is the process of generating a digital signature for a message using a private key. The signature can be
|
Signing is the process of generating a digital signature for a message using a private key. The signature can be verified
|
||||||
verified by others using the corresponding public key to ensure the message's integrity and authenticity. In Socialbox,
|
by others using the corresponding public key to ensure the message's integrity and authenticity. In Socialbox, signing
|
||||||
signing and signature verification are used to ensure the integrity of data exchanged between peers. The following
|
and signature verification are used to ensure the integrity of data exchanged between peers.
|
||||||
conditions apply to signing and signature verification:
|
|
||||||
|
|
||||||
* **Algorithm**: RSA with SHA256 hash function (SHA256withRSA)
|
* **Algorithm**: RSA with SHA256 hash function (SHA256withRSA)
|
||||||
* **Padding**: PKCS#1 v1.5 padding for signatures.
|
* **Padding**: PKCS#1 v1.5 padding for signatures.
|
||||||
|
@ -432,9 +436,10 @@ echo -n "Hello, World!" | openssl dgst -sha256 -verify public.der -signature sig
|
||||||
|
|
||||||
### Temporary Signature & Verification
|
### Temporary Signature & Verification
|
||||||
|
|
||||||
Temporary signatures work the same way as regular signatures, but the keypair used to sign the data is temporary and
|
Temporary signatures work similarly to regular signatures, but the keypair used to sign the data is temporary and only
|
||||||
is only used for a block of time, usually within 60 seconds. Temporary signatures are used to ensure the integrity of
|
valid for a limited time (typically 60 seconds). This feature ensures the integrity of data exchanged between peers
|
||||||
data exchanged between peers within a short period. The following conditions apply to temporary signatures:
|
within a short time window, adding protection against replay attacks. To ensure time synchronization, developers should
|
||||||
|
use NTP (Network Time Protocol).
|
||||||
|
|
||||||
* **Algorithm**: RSA with SHA256 hash function (SHA256withRSA)
|
* **Algorithm**: RSA with SHA256 hash function (SHA256withRSA)
|
||||||
* **Padding**: PKCS#1 v1.5 for signatures.
|
* **Padding**: PKCS#1 v1.5 for signatures.
|
||||||
|
@ -490,10 +495,9 @@ Hello, World!|28765051
|
||||||
|
|
||||||
### Encryption and Decryption
|
### Encryption and Decryption
|
||||||
|
|
||||||
Encryption is the process of converting plaintext data into ciphertext using a public key, while decryption is the
|
Encryption is the process of converting plaintext data into ciphertext using a public key, while decryption converts
|
||||||
process of converting ciphertext back into plaintext using the corresponding private key. In Socialbox, encryption and
|
ciphertext back into plaintext using the corresponding private key. In Socialbox, encryption and decryption ensure the
|
||||||
decryption are used to ensure the confidentiality of data exchanged between peers. The following conditions apply to
|
confidentiality of data exchanged between peers.
|
||||||
encryption and decryption:
|
|
||||||
|
|
||||||
* **Algorithm**: RSA with OAEP (Optimal Asymmetric Encryption Padding)
|
* **Algorithm**: RSA with OAEP (Optimal Asymmetric Encryption Padding)
|
||||||
* **Hash**: SHA256
|
* **Hash**: SHA256
|
||||||
|
@ -517,6 +521,13 @@ openssl rsautl -decrypt -oaep -inkey private_base64.txt -in ciphertext.bin
|
||||||
|
|
||||||
> Note: In this example, the produced ciphertext is binary data, but if you want to transmit the ciphertext over the
|
> Note: In this example, the produced ciphertext is binary data, but if you want to transmit the ciphertext over the
|
||||||
network, you must encode it using Base64 encoding.
|
network, you must encode it using Base64 encoding.
|
||||||
|
>
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
|
||||||
|
For real-world implementations, error handling should be a priority. For example, signature verification and decryption
|
||||||
|
can fail if the data is tampered with, keys don’t match, or the data has expired. Ensure that invalid signatures or
|
||||||
|
decryption errors are caught and handled appropriately to avoid security vulnerabilities
|
||||||
|
|
||||||
### Methods
|
### Methods
|
||||||
|
|
||||||
|
@ -525,12 +536,13 @@ The following methods should be implemented by all Socialbox servers and clients
|
||||||
#### generateKeyPair()
|
#### generateKeyPair()
|
||||||
|
|
||||||

|

|
||||||
Generates a new RSA key pair for encryption and decryption, returns the public and private keys in Base64 encoding.
|
Generates a new RSA key pair for encryption and decryption, returning the public and private keys in Base64 encoding.
|
||||||
|
|
||||||
#### signContent(content: String, privateKey: String): String
|
#### signContent(content: String, privateKey: String): String
|
||||||
|
|
||||||

|

|
||||||
Signs the content using the private key and returns the signature in Base64 encoding.
|
Signs the content using the private key and returns the signature in Base64 encoding.
|
||||||
|
The content is expected to be a UTF-8 encoded string.
|
||||||
|
|
||||||
#### verifyContent(content: String, signature: String, publicKey: String): Boolean
|
#### verifyContent(content: String, signature: String, publicKey: String): Boolean
|
||||||
|
|
||||||
|
@ -542,7 +554,7 @@ Verifies the signature of the content using the public key and returns true if t
|
||||||

|

|
||||||
Signs the content using a temporary private key and returns the temporary signature in Base64 encoding.
|
Signs the content using a temporary private key and returns the temporary signature in Base64 encoding.
|
||||||
|
|
||||||
### verifyTemporarySignature(content: String, signature: String, publicKey: String, frames: Integer): Boolean
|
#### verifyTemporarySignature(content: String, signature: String, publicKey: String, frames: Integer): Boolean
|
||||||
|
|
||||||

|

|
||||||
Verifies the temporary signature of the content using the public key and returns true if the signature is valid
|
Verifies the temporary signature of the content using the public key and returns true if the signature is valid
|
||||||
|
@ -558,6 +570,20 @@ Encrypts the content using the public key and returns the ciphertext in Base64 e
|
||||||

|

|
||||||
Decrypts the ciphertext using the private key and returns the plaintext content.
|
Decrypts the ciphertext using the private key and returns the plaintext content.
|
||||||
|
|
||||||
|
### Example Implementations
|
||||||
|
|
||||||
|
This standard provides examples of how to implement the cryptographic methods using OpenSSL or any other cryptographic
|
||||||
|
library that supports RSA encryption and decryption. The examples demonstrate how to generate RSA key pairs, sign and
|
||||||
|
verify content, and encrypt and decrypt data using RSA.
|
||||||
|
|
||||||
|
> Note: The examples provided are for demonstration purposes only. Developers should use a secure cryptographic library
|
||||||
|
and follow best practices to ensure the security of their implementations.
|
||||||
|
|
||||||
|
- [Python](examples/cryptography.py)
|
||||||
|
- [Java](examples/Cryptography.java)
|
||||||
|
- [PHP](examples/cryptography.php)
|
||||||
|
- [C](examples/cryptography.c)
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
# Authentication
|
# Authentication
|
||||||
|
|
69
examples/cryptography.c
Normal file
69
examples/cryptography.c
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
import java.security.*;
|
||||||
|
import java.util.Base64;
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
public class Cryptography {
|
||||||
|
|
||||||
|
// Generate a new RSA key pair
|
||||||
|
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
|
||||||
|
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||||
|
keyGen.initialize(2048);
|
||||||
|
return keyGen.generateKeyPair();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign the content using the private key
|
||||||
|
public static String signContent(String content, PrivateKey privateKey) throws Exception {
|
||||||
|
Signature privateSignature = Signature.getInstance("SHA256withRSA");
|
||||||
|
privateSignature.initSign(privateKey);
|
||||||
|
privateSignature.update(content.getBytes("UTF-8"));
|
||||||
|
byte[] signature = privateSignature.sign();
|
||||||
|
return Base64.getEncoder().encodeToString(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the signature of the content using the public key
|
||||||
|
public static boolean verifyContent(String content, String signature, PublicKey publicKey) throws Exception {
|
||||||
|
Signature publicSignature = Signature.getInstance("SHA256withRSA");
|
||||||
|
publicSignature.initVerify(publicKey);
|
||||||
|
publicSignature.update(content.getBytes("UTF-8"));
|
||||||
|
byte[] signatureBytes = Base64.getDecoder().decode(signature);
|
||||||
|
return publicSignature.verify(signatureBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign the content with a temporary signature based on time blocks
|
||||||
|
public static String temporarySignContent(String content, PrivateKey privateKey, int frames) throws Exception {
|
||||||
|
long timeBlock = Instant.now().getEpochSecond() / 60;
|
||||||
|
String contentWithTime = content + "|" + timeBlock;
|
||||||
|
return signContent(contentWithTime, privateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify a temporary signature with time blocks
|
||||||
|
public static boolean verifyTemporarySignature(String content, String signature, PublicKey publicKey, int frames) throws Exception {
|
||||||
|
long timeBlock = Instant.now().getEpochSecond() / 60;
|
||||||
|
|
||||||
|
for (int i = 0; i < frames; i++) {
|
||||||
|
String contentWithTime = content + "|" + (timeBlock - i);
|
||||||
|
if (verifyContent(contentWithTime, signature, publicKey)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt the content using the public key
|
||||||
|
public static String encryptContent(String content, PublicKey publicKey) throws Exception {
|
||||||
|
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||||
|
byte[] ciphertext = cipher.doFinal(content.getBytes("UTF-8"));
|
||||||
|
return Base64.getEncoder().encodeToString(ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt the content using the private key
|
||||||
|
public static String decryptContent(String ciphertext, PrivateKey privateKey) throws Exception {
|
||||||
|
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||||
|
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(ciphertext));
|
||||||
|
return new String(decryptedBytes, "UTF-8");
|
||||||
|
}
|
||||||
|
}
|
69
examples/cryptography.java
Normal file
69
examples/cryptography.java
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
import java.security.*;
|
||||||
|
import java.util.Base64;
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
public class Cryptography {
|
||||||
|
|
||||||
|
// Generate a new RSA key pair
|
||||||
|
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
|
||||||
|
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||||
|
keyGen.initialize(2048);
|
||||||
|
return keyGen.generateKeyPair();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign the content using the private key
|
||||||
|
public static String signContent(String content, PrivateKey privateKey) throws Exception {
|
||||||
|
Signature privateSignature = Signature.getInstance("SHA256withRSA");
|
||||||
|
privateSignature.initSign(privateKey);
|
||||||
|
privateSignature.update(content.getBytes("UTF-8"));
|
||||||
|
byte[] signature = privateSignature.sign();
|
||||||
|
return Base64.getEncoder().encodeToString(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the signature of the content using the public key
|
||||||
|
public static boolean verifyContent(String content, String signature, PublicKey publicKey) throws Exception {
|
||||||
|
Signature publicSignature = Signature.getInstance("SHA256withRSA");
|
||||||
|
publicSignature.initVerify(publicKey);
|
||||||
|
publicSignature.update(content.getBytes("UTF-8"));
|
||||||
|
byte[] signatureBytes = Base64.getDecoder().decode(signature);
|
||||||
|
return publicSignature.verify(signatureBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign the content with a temporary signature based on time blocks
|
||||||
|
public static String temporarySignContent(String content, PrivateKey privateKey, int frames) throws Exception {
|
||||||
|
long timeBlock = Instant.now().getEpochSecond() / 60;
|
||||||
|
String contentWithTime = content + "|" + timeBlock;
|
||||||
|
return signContent(contentWithTime, privateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify a temporary signature with time blocks
|
||||||
|
public static boolean verifyTemporarySignature(String content, String signature, PublicKey publicKey, int frames) throws Exception {
|
||||||
|
long timeBlock = Instant.now().getEpochSecond() / 60;
|
||||||
|
|
||||||
|
for (int i = 0; i < frames; i++) {
|
||||||
|
String contentWithTime = content + "|" + (timeBlock - i);
|
||||||
|
if (verifyContent(contentWithTime, signature, publicKey)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt the content using the public key
|
||||||
|
public static String encryptContent(String content, PublicKey publicKey) throws Exception {
|
||||||
|
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||||
|
byte[] ciphertext = cipher.doFinal(content.getBytes("UTF-8"));
|
||||||
|
return Base64.getEncoder().encodeToString(ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt the content using the private key
|
||||||
|
public static String decryptContent(String ciphertext, PrivateKey privateKey) throws Exception {
|
||||||
|
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||||
|
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(ciphertext));
|
||||||
|
return new String(decryptedBytes, "UTF-8");
|
||||||
|
}
|
||||||
|
}
|
120
examples/cryptography.php
Normal file
120
examples/cryptography.php
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Cryptography
|
||||||
|
{
|
||||||
|
// Generate a new RSA key pair
|
||||||
|
public static function generateKeyPair()
|
||||||
|
{
|
||||||
|
// Generate private key
|
||||||
|
$config = [
|
||||||
|
"private_key_type" => OPENSSL_KEYTYPE_RSA,
|
||||||
|
"private_key_bits" => 2048,
|
||||||
|
];
|
||||||
|
$res = openssl_pkey_new($config);
|
||||||
|
|
||||||
|
// Extract the private key to a variable
|
||||||
|
openssl_pkey_export($res, $privateKey);
|
||||||
|
|
||||||
|
// Extract the public key from the private key
|
||||||
|
$publicKeyDetails = openssl_pkey_get_details($res);
|
||||||
|
$publicKey = $publicKeyDetails['key'];
|
||||||
|
|
||||||
|
// Return both keys in Base64 encoding (without PEM headers)
|
||||||
|
return [
|
||||||
|
'privateKey' => base64_encode($privateKey),
|
||||||
|
'publicKey' => base64_encode($publicKey),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign the content using the private key
|
||||||
|
public static function signContent($content, $privateKey)
|
||||||
|
{
|
||||||
|
// Decode the Base64 private key
|
||||||
|
$privateKeyDecoded = openssl_pkey_get_private(base64_decode($privateKey));
|
||||||
|
|
||||||
|
// Sign the content
|
||||||
|
openssl_sign($content, $signature, $privateKeyDecoded, OPENSSL_ALGO_SHA256);
|
||||||
|
|
||||||
|
// Return the signature in Base64 encoding
|
||||||
|
return base64_encode($signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the signature of the content using the public key
|
||||||
|
public static function verifyContent($content, $signature, $publicKey)
|
||||||
|
{
|
||||||
|
// Decode the Base64 public key
|
||||||
|
$publicKeyDecoded = openssl_pkey_get_public(base64_decode($publicKey));
|
||||||
|
|
||||||
|
// Decode the Base64 signature
|
||||||
|
$signatureDecoded = base64_decode($signature);
|
||||||
|
|
||||||
|
// Verify the signature
|
||||||
|
$result = openssl_verify($content, $signatureDecoded, $publicKeyDecoded, OPENSSL_ALGO_SHA256);
|
||||||
|
|
||||||
|
// Return true if the signature is valid, false otherwise
|
||||||
|
return $result === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign the content with a temporary signature based on time blocks
|
||||||
|
public static function temporarySignContent($content, $privateKey, $frames = 1)
|
||||||
|
{
|
||||||
|
// Calculate the current time block
|
||||||
|
$timeBlock = intdiv(time(), 60);
|
||||||
|
|
||||||
|
// Append the time block to the content
|
||||||
|
$contentWithTime = $content . '|' . $timeBlock;
|
||||||
|
|
||||||
|
// Sign the content with the time block
|
||||||
|
return self::signContent($contentWithTime, $privateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify a temporary signature with time blocks
|
||||||
|
public static function verifyTemporarySignature($content, $signature, $publicKey, $frames = 1)
|
||||||
|
{
|
||||||
|
// Calculate the current time block
|
||||||
|
$timeBlock = intdiv(time(), 60);
|
||||||
|
|
||||||
|
// Check for each time block within the frame range
|
||||||
|
for ($i = 0; $i < $frames; $i++) {
|
||||||
|
// Append the time block to the content
|
||||||
|
$contentWithTime = $content . '|' . ($timeBlock - $i);
|
||||||
|
|
||||||
|
// Verify the signature
|
||||||
|
if (self::verifyContent($contentWithTime, $signature, $publicKey)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return false if none of the frames matched
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt the content using the public key
|
||||||
|
public static function encryptContent($content, $publicKey)
|
||||||
|
{
|
||||||
|
// Decode the Base64 public key
|
||||||
|
$publicKeyDecoded = openssl_pkey_get_public(base64_decode($publicKey));
|
||||||
|
|
||||||
|
// Encrypt the content
|
||||||
|
openssl_public_encrypt($content, $ciphertext, $publicKeyDecoded, OPENSSL_PKCS1_OAEP_PADDING);
|
||||||
|
|
||||||
|
// Return the ciphertext in Base64 encoding
|
||||||
|
return base64_encode($ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt the content using the private key
|
||||||
|
public static function decryptContent($ciphertext, $privateKey)
|
||||||
|
{
|
||||||
|
// Decode the Base64 private key
|
||||||
|
$privateKeyDecoded = openssl_pkey_get_private(base64_decode($privateKey));
|
||||||
|
|
||||||
|
// Decode the Base64 ciphertext
|
||||||
|
$ciphertextDecoded = base64_decode($ciphertext);
|
||||||
|
|
||||||
|
// Decrypt the content
|
||||||
|
openssl_private_decrypt($ciphertextDecoded, $plaintext, $privateKeyDecoded, OPENSSL_PKCS1_OAEP_PADDING);
|
||||||
|
|
||||||
|
// Return the decrypted plaintext
|
||||||
|
return $plaintext;
|
||||||
|
}
|
||||||
|
}
|
101
examples/cryptography.py
Normal file
101
examples/cryptography.py
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
import base64
|
||||||
|
import time
|
||||||
|
from Crypto.PublicKey import RSA
|
||||||
|
from Crypto.Signature import pkcs1_15
|
||||||
|
from Crypto.Hash import SHA256
|
||||||
|
from Crypto.Cipher import PKCS1_OAEP
|
||||||
|
|
||||||
|
class Cryptography:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_key_pair():
|
||||||
|
# Generate RSA key pair
|
||||||
|
key = RSA.generate(2048)
|
||||||
|
private_key = key.export_key(format='DER')
|
||||||
|
public_key = key.publickey().export_key(format='DER')
|
||||||
|
|
||||||
|
# Return keys in Base64 encoding
|
||||||
|
return {
|
||||||
|
'privateKey': base64.b64encode(private_key).decode('utf-8'),
|
||||||
|
'publicKey': base64.b64encode(public_key).decode('utf-8')
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sign_content(content, private_key_base64):
|
||||||
|
# Decode the Base64 private key
|
||||||
|
private_key = RSA.import_key(base64.b64decode(private_key_base64))
|
||||||
|
|
||||||
|
# Hash the content using SHA256
|
||||||
|
h = SHA256.new(content.encode('utf-8'))
|
||||||
|
|
||||||
|
# Sign the hash
|
||||||
|
signature = pkcs1_15.new(private_key).sign(h)
|
||||||
|
|
||||||
|
# Return the signature in Base64 encoding
|
||||||
|
return base64.b64encode(signature).decode('utf-8')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def verify_content(content, signature_base64, public_key_base64):
|
||||||
|
# Decode the Base64 public key and signature
|
||||||
|
public_key = RSA.import_key(base64.b64decode(public_key_base64))
|
||||||
|
signature = base64.b64decode(signature_base64)
|
||||||
|
|
||||||
|
# Hash the content
|
||||||
|
h = SHA256.new(content.encode('utf-8'))
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Verify the signature
|
||||||
|
pkcs1_15.new(public_key).verify(h, signature)
|
||||||
|
return True
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def temporary_sign_content(content, private_key_base64, frames=1):
|
||||||
|
# Calculate the current time block
|
||||||
|
time_block = int(time.time() // 60)
|
||||||
|
|
||||||
|
# Append the time block to the content
|
||||||
|
content_with_time = f"{content}|{time_block}"
|
||||||
|
|
||||||
|
# Sign the content with the time block
|
||||||
|
return Cryptography.sign_content(content_with_time, private_key_base64)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def verify_temporary_signature(content, signature_base64, public_key_base64, frames=1):
|
||||||
|
# Calculate the current time block
|
||||||
|
time_block = int(time.time() // 60)
|
||||||
|
|
||||||
|
# Check for each time block within the frame range
|
||||||
|
for i in range(frames):
|
||||||
|
content_with_time = f"{content}|{time_block - i}"
|
||||||
|
if Cryptography.verify_content(content_with_time, signature_base64, public_key_base64):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def encrypt_content(content, public_key_base64):
|
||||||
|
# Decode the Base64 public key
|
||||||
|
public_key = RSA.import_key(base64.b64decode(public_key_base64))
|
||||||
|
|
||||||
|
# Encrypt the content using RSA-OAEP
|
||||||
|
cipher = PKCS1_OAEP.new(public_key)
|
||||||
|
ciphertext = cipher.encrypt(content.encode('utf-8'))
|
||||||
|
|
||||||
|
# Return the ciphertext in Base64 encoding
|
||||||
|
return base64.b64encode(ciphertext).decode('utf-8')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def decrypt_content(ciphertext_base64, private_key_base64):
|
||||||
|
# Decode the Base64 private key and ciphertext
|
||||||
|
private_key = RSA.import_key(base64.b64decode(private_key_base64))
|
||||||
|
ciphertext = base64.b64decode(ciphertext_base64)
|
||||||
|
|
||||||
|
# Decrypt the content using RSA-OAEP
|
||||||
|
cipher = PKCS1_OAEP.new(private_key)
|
||||||
|
plaintext = cipher.decrypt(ciphertext)
|
||||||
|
|
||||||
|
# Return the decrypted content
|
||||||
|
return plaintext.decode('utf-8')
|
||||||
|
|
Loading…
Add table
Reference in a new issue