Improved Cryptography section and included samples in Java, C, PHP And Python

This commit is contained in:
netkas 2024-09-09 19:18:39 -04:00
parent 6c5ae90b1f
commit 144044a551
5 changed files with 407 additions and 22 deletions

View file

@ -69,6 +69,7 @@ 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)
@ -77,6 +78,7 @@ This project is licensed under GNU Free Documentation License v1.3, see the [LIC
* [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 dont 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()
![generateKeyPair Diagram](images/generateKeyPair.png "generateKeyPair Diagram") ![generateKeyPair Diagram](images/generateKeyPair.png "generateKeyPair Diagram")
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
![signContent Diagram](images/signContent.png "signContent Diagram") ![signContent Diagram](images/signContent.png "signContent Diagram")
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
![temporarySignContent Diagram](images/temporarySignContent.png "temporarySignContent Diagram") ![temporarySignContent Diagram](images/temporarySignContent.png "temporarySignContent Diagram")
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
![verifyTemproarySignature Diagram](images/verifyTemproarySignature.png "verifyTemporarySignature") ![verifyTemproarySignature Diagram](images/verifyTemproarySignature.png "verifyTemporarySignature")
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
![decryptContent Diagram](images/decryptContent.png "decryptContent Diagram") ![decryptContent Diagram](images/decryptContent.png "decryptContent Diagram")
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
View 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");
}
}

View 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
View 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
View 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')