Class: Capsium::Package::Cipher
- Inherits:
-
Object
- Object
- Capsium::Package::Cipher
- Defined in:
- lib/capsium/package/cipher.rb,
sig/capsium/package/cipher.rbs
Overview
Encrypts and decrypts whole Capsium packages (05x-packaging "Encryption", 05x-security "Encrypted information"). An encrypted .cap is a zip containing metadata.json (cleartext), signature.json (the encryption envelope) and package.enc (AES-256-GCM of the inner plaintext .cap zip). The random DEK is wrapped with the recipient's RSA public key using OAEP with SHA-256. OCB/OpenPGP are out of scope.
Direct Known Subclasses
Defined Under Namespace
Classes: CipherError, DecryptionError, KeyRequiredError
Constant Summary collapse
- ALGORITHM =
"AES-256-GCM"- KEY_MANAGEMENT =
"RSA-OAEP-SHA256"- ENCRYPTED_FILE =
"package.enc"- ENVELOPE_FILE =
"signature.json"- RSA_OPTIONS =
{ "rsa_padding_mode" => "oaep", "rsa_oaep_md" => "SHA256", "rsa_mgf1_md" => "SHA256" }.freeze
- CIPHER_NAME =
Class Method Summary collapse
-
.decrypt_to_directory(source_path, private_key_path) ⇒ String
Decrypts an encrypted package into a fresh temporary directory and returns the directory path.
-
.encrypted?(path) ⇒ Boolean
Whether the path (.cap file or uncompressed directory) is an encrypted package, i.e.
-
.for_encrypted(path) ⇒ Cipher
The cipher instance matching the envelope's keyManagement: OpenPgpCipher for OpenPGP envelopes, the RSA cipher otherwise.
-
.key_management(path) ⇒ String?
The keyManagement declared by the encryption envelope of the path (.cap file or uncompressed directory), or nil when the envelope is absent or unreadable.
Instance Method Summary collapse
-
#decrypt(encrypted_path, private_key_path, output_path) ⇒ String
Decrypts the encrypted package at encrypted_path (.cap file or uncompressed directory) with the recipient's RSA private key and writes the plaintext .cap to output_path.
-
#encrypt(source_path, public_key_path, output_path) ⇒ String
Encrypts the package at source_path (a .cap file, or a package directory which is packed first) for the recipient's RSA public key (or X.509 certificate) and writes the encrypted .cap to output_path.
Class Method Details
.decrypt_to_directory(source_path, private_key_path) ⇒ String
Decrypts an encrypted package into a fresh temporary directory and returns the directory path. The cipher is selected from the envelope's keyManagement: OpenPGP envelopes decrypt through OpenPgpCipher, everything else through the RSA cipher.
123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/capsium/package/cipher.rb', line 123 def self.decrypt_to_directory(source_path, private_key_path) Dir.mktmpdir.tap do |tmp| inner_cap = File.join(tmp, "inner.cap") for_encrypted(source_path).decrypt(source_path, private_key_path, inner_cap) package_path = File.join(tmp, File.basename(source_path.to_s, ".cap")) FileUtils.mkdir_p(package_path) Packager.new.unpack(inner_cap, package_path) FileUtils.rm_f(inner_cap) return package_path end end |
.encrypted?(path) ⇒ Boolean
Whether the path (.cap file or uncompressed directory) is an encrypted package, i.e. contains package.enc.
57 58 59 60 61 62 63 64 |
# File 'lib/capsium/package/cipher.rb', line 57 def self.encrypted?(path) return File.file?(File.join(path, ENCRYPTED_FILE)) if File.directory?(path) return false unless File.file?(path) Zip::File.open(path) { |zip| !zip.find_entry(ENCRYPTED_FILE).nil? } rescue Zip::Error false end |
.for_encrypted(path) ⇒ Cipher
The cipher instance matching the envelope's keyManagement: OpenPgpCipher for OpenPGP envelopes, the RSA cipher otherwise.
78 79 80 |
# File 'lib/capsium/package/cipher.rb', line 78 def self.for_encrypted(path) key_management(path) == OpenPgpCipher::KEY_MANAGEMENT ? OpenPgpCipher.new : new end |
.key_management(path) ⇒ String?
The keyManagement declared by the encryption envelope of the path (.cap file or uncompressed directory), or nil when the envelope is absent or unreadable.
69 70 71 72 73 74 |
# File 'lib/capsium/package/cipher.rb', line 69 def self.key_management(path) source = envelope_source(path) source && EncryptionConfig.from_json(source).encryption&.key_management rescue Lutaml::Model::Error, JSON::ParserError nil end |
Instance Method Details
#decrypt(encrypted_path, private_key_path, output_path) ⇒ String
Decrypts the encrypted package at encrypted_path (.cap file or uncompressed directory) with the recipient's RSA private key and writes the plaintext .cap to output_path. Returns output_path.
110 111 112 113 114 115 116 |
# File 'lib/capsium/package/cipher.rb', line 110 def decrypt(encrypted_path, private_key_path, output_path) private_key = load_private_key(private_key_path) envelope = load_envelope(encrypted_path) ciphertext = read_source(encrypted_path, ENCRYPTED_FILE) File.binwrite(output_path, decrypt_bytes(ciphertext, envelope, private_key)) output_path end |
#encrypt(source_path, public_key_path, output_path) ⇒ String
Encrypts the package at source_path (a .cap file, or a package directory which is packed first) for the recipient's RSA public key (or X.509 certificate) and writes the encrypted .cap to output_path. Returns output_path.
97 98 99 100 101 102 103 104 105 |
# File 'lib/capsium/package/cipher.rb', line 97 def encrypt(source_path, public_key_path, output_path) public_key = load_public_key(public_key_path) with_cap_file(source_path) do |cap_path| envelope, ciphertext = encrypt_bytes(File.binread(cap_path), public_key) write_encrypted_cap(output_path, read_source(cap_path, Package::METADATA_FILE), envelope, ciphertext) end output_path end |