Class: Parallel::Serializer::Hmac
- Inherits:
-
Object
- Object
- Parallel::Serializer::Hmac
- Defined in:
- lib/parallel/serializer.rb
Overview
Wraps any inner serializer with a length-prefixed HMAC-SHA256 frame keyed on a per-worker secret generated before fork. Forged frames from a pipe-injector fail verification.
Constant Summary collapse
- LENGTH_FORMAT =
32-bit big-endian unsigned int
'N'- LENGTH_BYTES =
4- MAC_BYTES =
SHA256
32
Instance Method Summary collapse
- #dump(data, io) ⇒ Object
-
#initialize(inner: Marshal, secret: SecureRandom.bytes(32)) ⇒ Hmac
constructor
A new instance of Hmac.
- #load(io) ⇒ Object
Constructor Details
Instance Method Details
#dump(data, io) ⇒ Object
27 28 29 30 31 |
# File 'lib/parallel/serializer.rb', line 27 def dump(data, io) payload = @inner.dump(data) mac = OpenSSL::HMAC.digest('SHA256', @secret, payload) io.write([payload.bytesize].pack(LENGTH_FORMAT), mac, payload) end |
#load(io) ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/parallel/serializer.rb', line 33 def load(io) # nil at frame boundary = clean EOF (worker died / pipe closed between messages) header = io.read(LENGTH_BYTES) || raise(EOFError) # eof stops worker raise SecurityError, "truncated frame header" if header.bytesize != LENGTH_BYTES length = header.unpack1(LENGTH_FORMAT) mac = io.read(MAC_BYTES) raise SecurityError, "truncated frame mac" if mac.nil? || mac.bytesize != MAC_BYTES payload = io.read(length) raise SecurityError, "truncated frame payload" if payload.nil? || payload.bytesize != length expected = OpenSSL::HMAC.digest('SHA256', @secret, payload) raise SecurityError, "HMAC mismatch on worker pipe" unless OpenSSL.fixed_length_secure_compare(mac, expected) @inner.load(payload) end |