PKCS#7 Signing: How to get repeatable output for signing the same data

Tim Meusel openssl at bastelfreak.de
Mon Oct 17 08:28:45 UTC 2022


Hi!
I maintain a Ruby script that does PKCS#7 signing and afterwards some 
enryption with AES-128-CFB. A trimmed down version:

certpath = '/tmp/cert.pem'
keypath = '/tmp/key/pem'
data = 'teststring'
key  = OpenSSL::PKey::RSA.new(File.read(keypath), '1234')
cert = OpenSSL::X509::Certificate.new(File.read(certpath))
signed = OpenSSL::PKCS7::sign(cert, key, data, [], OpenSSL::PKCS7::BINARY)
cipher = OpenSSL::Cipher::new("AES-128-CFB")
iv_len = cipher.iv_len
key_len = cipher.key_len
fqdn_rand = Digest::SHA256.hexdigest([destination,data.length].join(':'))
iv_seed, key_seed = fqdn_rand.partition(/.{32}/)[1,2]
iv = iv_seed.unpack('a2'*key_len).map{|x| x.hex}.pack('c'*key_len)
key = key_seed.unpack('a2'*key_len).map{|x| x.hex}.pack('c'*key_len)
cipher.encrypt
cipher.iv=(iv)
cipher.key=(key)
OpenSSL::PKCS7::encrypt([target], signed.to_der, cipher, 
OpenSSL::PKCS7::BINARY).to_s

I pulled the AES encryption into a testscript and that's indeed 
repeatable (script at the end of the email). I did some tests and 
noticed that the initial signing doesn't produce repeatable output:

signed = OpenSSL::PKCS7::sign(cert, key, data, [], OpenSSL::PKCS7::BINARY)

I did some googling and that told me the signing date/timestamp is part 
of the output, which would explain why it doesn't produce the same 
output when I run it twice. Now to my actual questions:
* Is the different output caused by a changing signing time and/or 
something else?
* Do you know if I can pass the signingtime to manipulate it?

I know that this isn't a Ruby mailinglist, but the ruby-openssl bindings 
and the documentation are generated from the C code and were not very 
helpful (for people not knowing C/not knowing a lot about 
OpenSSL/PKCS#7). Maybe you've some thoughts.

Why am I doing this?

Roughly explained, the script is executed every 30 minutes for a lot of 
content, then the previous PKCS#7 output is pulled from a database, 
compared, and if the new script output is different, the DB is updated. 
This is stupid in many ways, but I cannot change that short-term. As a 
workarond, we would like to update the script to produce repeatable 
output. I know that this weakens the security, but we need to reduce the 
database load from the many reoccurring updates.

my AES testing:

root at puppet ~ # ruby openssl.rb
encrypted: ["38b5cefb"]
decrypted: test
encrypted: ["38b5cefb"]
decrypted: test
root at puppet ~ # cat openssl.rb
#!/usr/bin/env ruby

require 'openssl'

def encrypt(content)
   cipher = OpenSSL::Cipher::new("AES-128-CFB")
   cipher.encrypt
   iv ="00000000000000000000000000000001".unpack('a2'*16).map{|x| 
x.hex}.pack('c'*16)
   cipher.iv=(iv)
   key = "7ffb8032dff33aef9aa92e9ac96239d3".unpack('a2'*16).map{|x| 
x.hex}.pack('c'*16)
   cipher.key=(key)
   output = cipher.update(content)
   output << cipher.final
   puts "encrypted: #{output.unpack('H*')}\n"
   puts "decrypted: #{decrypt(output, iv, key)}\n"
end

def decrypt(content, iv, key)
   cipher = OpenSSL::Cipher::new("AES-128-CFB")
   cipher.decrypt
   cipher.iv=(iv)
   cipher.key=(key)
   output = cipher.update(content)
   output << cipher.final
   output
end
encrypt 'test'
encrypt 'test'
root at puppet ~ #

The complete original code:
https://github.com/binford2k/binford2k-node_encrypt/blob/main/lib/puppet_x/binford2k/node_encrypt.rb#L11-L55
My WIP patch: 
https://github.com/binford2k/binford2k-node_encrypt/compare/main...bastelfreak:binford2k-node_encrypt:49675?expand=1

Cheers, Tim
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature
Type: application/pgp-signature
Size: 495 bytes
Desc: OpenPGP digital signature
URL: <https://mta.openssl.org/pipermail/openssl-users/attachments/20221017/0c1827b5/attachment.sig>


More information about the openssl-users mailing list