Class: Lanet::Encryptor
- Inherits:
-
Object
- Object
- Lanet::Encryptor
- Defined in:
- lib/lanet/encryptor.rb
Overview
Encryptor class for message encryption/decryption and signing
Defined Under Namespace
Modules: MessageType Classes: Error
Constant Summary collapse
- ENCRYPTED_PREFIX =
Message type prefixes
"E"- PLAINTEXT_PREFIX =
"P"- SIGNED_ENCRYPTED_PREFIX =
"SE"- SIGNED_PLAINTEXT_PREFIX =
"SP"- SIGNATURE_DELIMITER =
Delimiters and sizes
"||SIG||"
Class Method Summary collapse
-
.decrypt_data(content, key) ⇒ String
Decrypt encrypted content.
-
.derive_key(key) ⇒ String
Derive a key from the provided password.
-
.encrypt_data(data, key) ⇒ String
Encrypt data with the given key.
-
.parse_message_type(data) ⇒ Array<Symbol, String>
Parse the message type from the prefix.
-
.prepare_encrypted(message, key) ⇒ Object
Prepare an encrypted but unsigned message.
-
.prepare_message(message, encryption_key, private_key = nil) ⇒ String
Prepares a message with encryption and/or signing.
-
.prepare_plaintext(message) ⇒ Object
Prepare a plaintext message.
-
.prepare_signed_encrypted(message, encryption_key, private_key) ⇒ Object
Prepare a signed and encrypted message.
-
.prepare_signed_plaintext(message, private_key) ⇒ Object
Prepare a signed but unencrypted message.
-
.process_encrypted_message(content, encryption_key) ⇒ Object
Process an encrypted message.
-
.process_message(data, encryption_key = nil, public_key = nil) ⇒ Hash
Processes a message, decrypting and verifying if necessary.
-
.process_signed_content(content, public_key) ⇒ Object
Process content that contains a signature.
-
.process_signed_encrypted_message(content, encryption_key, public_key) ⇒ Object
Process a signed and encrypted message.
-
.validate_key_length(key) ⇒ Object
Validate key length.
Class Method Details
.decrypt_data(content, key) ⇒ String
Decrypt encrypted content
206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/lanet/encryptor.rb', line 206 def self.decrypt_data(content, key) decoded = Base64.strict_decode64(content) iv = decoded[0...Config::IV_SIZE] ciphertext = decoded[Config::IV_SIZE..] decipher = OpenSSL::Cipher.new(Config::CIPHER_ALGORITHM) decipher.decrypt decipher.key = derive_key(key) decipher.iv = iv decipher.update(ciphertext) + decipher.final rescue StandardError => e raise Error, "Decryption failed: #{e.}" end |
.derive_key(key) ⇒ String
Derive a key from the provided password
189 190 191 192 193 |
# File 'lib/lanet/encryptor.rb', line 189 def self.derive_key(key) validate_key_length(key) digest = OpenSSL::Digest.new("SHA256") OpenSSL::PKCS5.pbkdf2_hmac(key, "salt", 1000, Config::KEY_SIZE, digest) end |
.encrypt_data(data, key) ⇒ String
Encrypt data with the given key
84 85 86 87 88 89 90 91 92 93 |
# File 'lib/lanet/encryptor.rb', line 84 def self.encrypt_data(data, key) cipher = OpenSSL::Cipher.new(Config::CIPHER_ALGORITHM) cipher.encrypt cipher.key = derive_key(key) iv = cipher.random_iv encrypted = cipher.update(data) + cipher.final Base64.strict_encode64(iv + encrypted) rescue StandardError => e raise Error, "Encryption failed: #{e.}" end |
.parse_message_type(data) ⇒ Array<Symbol, String>
Parse the message type from the prefix
122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/lanet/encryptor.rb', line 122 def self.(data) # Check for two-character prefixes first if data.length > 1 && data[0..1] == SIGNED_ENCRYPTED_PREFIX [MessageType::SIGNED_ENCRYPTED, data[2..]] elsif data.length > 1 && data[0..1] == SIGNED_PLAINTEXT_PREFIX [MessageType::SIGNED_PLAINTEXT, data[2..]] elsif data[0] == ENCRYPTED_PREFIX [MessageType::ENCRYPTED, data[1..]] elsif data[0] == PLAINTEXT_PREFIX [MessageType::PLAINTEXT, data[1..]] else [nil, data] end end |
.prepare_encrypted(message, key) ⇒ Object
Prepare an encrypted but unsigned message
60 61 62 63 |
# File 'lib/lanet/encryptor.rb', line 60 def self.prepare_encrypted(, key) encrypted_data = encrypt_data(, key) "#{ENCRYPTED_PREFIX}#{encrypted_data}" end |
.prepare_message(message, encryption_key, private_key = nil) ⇒ String
Prepares a message with encryption and/or signing
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/lanet/encryptor.rb', line 37 def self.(, encryption_key, private_key = nil) = .to_s has_encryption = !encryption_key.nil? && !encryption_key.empty? has_signature = !private_key.nil? && !private_key.empty? case [has_signature, has_encryption] when [false, false] prepare_plaintext() when [false, true] prepare_encrypted(, encryption_key) when [true, false] prepare_signed_plaintext(, private_key) when [true, true] prepare_signed_encrypted(, encryption_key, private_key) end end |
.prepare_plaintext(message) ⇒ Object
Prepare a plaintext message
55 56 57 |
# File 'lib/lanet/encryptor.rb', line 55 def self.prepare_plaintext() "#{PLAINTEXT_PREFIX}#{}" end |
.prepare_signed_encrypted(message, encryption_key, private_key) ⇒ Object
Prepare a signed and encrypted message
73 74 75 76 77 78 |
# File 'lib/lanet/encryptor.rb', line 73 def self.prepare_signed_encrypted(, encryption_key, private_key) signature = Signer.sign(, private_key) = "#{}#{SIGNATURE_DELIMITER}#{signature}" encrypted_data = encrypt_data(, encryption_key) "#{SIGNED_ENCRYPTED_PREFIX}#{encrypted_data}" end |
.prepare_signed_plaintext(message, private_key) ⇒ Object
Prepare a signed but unencrypted message
66 67 68 69 70 |
# File 'lib/lanet/encryptor.rb', line 66 def self.prepare_signed_plaintext(, private_key) signature = Signer.sign(, private_key) = "#{}#{SIGNATURE_DELIMITER}#{signature}" "#{SIGNED_PLAINTEXT_PREFIX}#{}" end |
.process_encrypted_message(content, encryption_key) ⇒ Object
Process an encrypted message
138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/lanet/encryptor.rb', line 138 def self.(content, encryption_key) if encryption_key.nil? || encryption_key.strip.empty? { content: "[Encrypted message received, but no key provided]", verified: false } else begin decrypted = decrypt_data(content, encryption_key) { content: decrypted, verified: false } rescue Error => e { content: "Decryption failed: #{e.}", verified: false } end end end |
.process_message(data, encryption_key = nil, public_key = nil) ⇒ Hash
Processes a message, decrypting and verifying if necessary
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/lanet/encryptor.rb', line 100 def self.(data, encryption_key = nil, public_key = nil) return { content: "[Empty message]", verified: false } if data.nil? || data.empty? , content = (data) case when MessageType::ENCRYPTED (content, encryption_key) when MessageType::PLAINTEXT { content: content, verified: false } when MessageType::SIGNED_ENCRYPTED (content, encryption_key, public_key) when MessageType::SIGNED_PLAINTEXT process_signed_content(content, public_key) else { content: "[Invalid message format]", verified: false } end end |
.process_signed_content(content, public_key) ⇒ Object
Process content that contains a signature
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/lanet/encryptor.rb', line 166 def self.process_signed_content(content, public_key) if content.include?(SIGNATURE_DELIMITER) , signature = content.split(SIGNATURE_DELIMITER, 2) if public_key.nil? || public_key.strip.empty? { content: , verified: false, verification_status: "No public key provided for verification" } else begin verified = Signer.verify(, signature, public_key) { content: , verified: verified, verification_status: verified ? "Verified" : "Signature verification failed" } rescue StandardError => e { content: , verified: false, verification_status: "Verification error: #{e.}" } end end else { content: content, verified: false, verification_status: "No signature found" } end end |
.process_signed_encrypted_message(content, encryption_key, public_key) ⇒ Object
Process a signed and encrypted message
152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/lanet/encryptor.rb', line 152 def self.(content, encryption_key, public_key) if encryption_key.nil? || encryption_key.strip.empty? { content: "[Signed encrypted message received, but no encryption key provided]", verified: false } else begin decrypted = decrypt_data(content, encryption_key) process_signed_content(decrypted, public_key) rescue Error => e { content: "Processing signed encrypted message failed: #{e.}", verified: false } end end end |
.validate_key_length(key) ⇒ Object
Validate key length
196 197 198 199 200 |
# File 'lib/lanet/encryptor.rb', line 196 def self.validate_key_length(key) return unless key && key.length > Config::MAX_KEY_LENGTH raise Error, "Encryption key is too long (maximum #{Config::MAX_KEY_LENGTH} characters)" end |