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,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)
* [Temporary Signature & Verification](#temporary-signature--verification)
* [Encryption and Decryption](#encryption-and-decryption)
* [Error Handling](#error-handling)
* [Methods](#methods)
* [generateKeyPair()](#generatekeypair)
* [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)
* [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)
* [decryptContent(ciphertext: String, privateKey: String): String](#decryptcontentciphertext-string-privatekey-string-string)
* [Example Implementations](#example-implementations)
* [Authentication](#authentication)
* [First-Level Authentication](#first-level-authentication)
* [Password (LOGIN)](#password-login)
@ -350,21 +352,24 @@ The fields in the error response object are as follows:
## Cryptography
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
things simple, every Socialbox client & server must implement the same cryptographic methods to ensure compatibility
with other systems. Mainly, the Socialbox standard uses the following cryptographic methods:
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. Every
Socialbox client & server must implement the same cryptographic methods to ensure compatibility with other systems.
Mainly, the Socialbox standard uses the following cryptographic methods:
* **RSA**: Used for asymmetric encryption and decryption.
* **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.
> 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 is the process of generating cryptographic keys for encryption and decryption. In Socialbox, RSA keys
are used for asymmetric encryption and decryption. The key generation process involves generating a public key and a
private key. The public key can be shared with others to encrypt/verify data, while the private key is kept secret and
used to decrypt/sign data. These are the following conditions for key generation:
Key generation is the process of generating cryptographic keys for encryption and decryption. In Socialbox, RSA keys are
used for asymmetric encryption and decryption. The key generation process involves generating a public key and a private
key. The public key can be shared with others to encrypt/verify data, while the private key is kept secret and used to
decrypt/sign data. These are the following conditions for key generation:
* **Key Size**: The key size must be 2048 bits.
* **Algorithm**: The algorithm used for key generation must be RSA.
@ -399,10 +404,9 @@ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQ...
### Signing and Signature Verification
Signing is the process of generating a digital signature for a message using a private key. The signature can be
verified by others using the corresponding public key to ensure the message's integrity and authenticity. In Socialbox,
signing and signature verification are used to ensure the integrity of data exchanged between peers. The following
conditions apply to signing and signature verification:
Signing is the process of generating a digital signature for a message using a private key. The signature can be verified
by others using the corresponding public key to ensure the message's integrity and authenticity. In Socialbox, signing
and signature verification are used to ensure the integrity of data exchanged between peers.
* **Algorithm**: RSA with SHA256 hash function (SHA256withRSA)
* **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 signatures work the same way as regular signatures, but the keypair used to sign the data is temporary and
is only used for a block of time, usually within 60 seconds. Temporary signatures are used to ensure the integrity of
data exchanged between peers within a short period. The following conditions apply to temporary signatures:
Temporary signatures work similarly to regular signatures, but the keypair used to sign the data is temporary and only
valid for a limited time (typically 60 seconds). This feature ensures the integrity of data exchanged between peers
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)
* **Padding**: PKCS#1 v1.5 for signatures.
@ -490,10 +495,9 @@ Hello, World!|28765051
### Encryption and Decryption
Encryption is the process of converting plaintext data into ciphertext using a public key, while decryption is the
process of converting ciphertext back into plaintext using the corresponding private key. In Socialbox, encryption and
decryption are used to ensure the confidentiality of data exchanged between peers. The following conditions apply to
encryption and decryption:
Encryption is the process of converting plaintext data into ciphertext using a public key, while decryption converts
ciphertext back into plaintext using the corresponding private key. In Socialbox, encryption and decryption ensure the
confidentiality of data exchanged between peers.
* **Algorithm**: RSA with OAEP (Optimal Asymmetric Encryption Padding)
* **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
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
@ -525,12 +536,13 @@ The following methods should be implemented by all Socialbox servers and clients
#### generateKeyPair()
![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 Diagram](images/signContent.png "signContent Diagram")
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
@ -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")
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")
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")
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

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