changing key trust level (validity) with gpgme - gnupg

GPGME provides information about a key's trust level as the owner_trust field which is of gpgme_validity_t type. However, I could not find a function in the documentation or the gpgme.h header file that allows me to change the validity of a key.
The GnuPG command line tool sure allows to change the trust level of a key:
$ gpg --edit-key alice#example.com
> trust
Does the GPGME library even support changing the owner_trust field? If so, how do I use it?
I am using the newest version of GPGME which is 1.16.0 (commit hash 1021c8645555502d914afffaa3707609809c9459).

It should be possible to use gpgme_op_interact to accomplish this.
The following demonstrates the process with Python bindings, but analogous code should be possible to write with the C API.
import gpg
def trust_at(level):
done = False
def interact_cb(status, arg):
nonlocal done
if status in ('KEY_CONSIDERED', 'GOT_IT', ''):
return
if status == 'GET_LINE':
if arg == 'keyedit.prompt':
if done:
return 'quit'
done = True
return 'trust'
if arg == 'edit_ownertrust.value':
return level
# needed if we set trust level to 5
if (status, arg) == ('GET_BOOL', 'edit_ownertrust.set_ultimate.okay'):
return 'y'
assert False
return interact_cb
with gpg.Context() as gnupg:
key = gnupg.get_key(FINGERPRINT)
gnupg.interact(key, trust_at('4'))

Related

Does Redis have Set with condition?

I am looking for something like this:
update data
set data = new_data
where data.updated_at < new_data.updated_at
I can't find a solution for this problem,
The close one is to use WATCH but unfortunately it can't watch for specific value condition.
If redis can't do this, do you have any recommended in memory like Redis that support this feature?
You can do this with Lua Scripts, using EVAL command
Assuming you want to set both the update timestamp and the data value, and if no timestamp also set the values (for first-time set), the Lua script can be something like:
local updt = redis.call('GET', KEYS[1])
if (not updt) or (tonumber(updt) < tonumber(ARGV[1])) then
return redis.call('MSET', KEYS[1], ARGV[1], KEYS[2], ARGV[2])
else
return redis.error_reply('data is newer on server!')
end
You can invoke as:
EVAL "local updt = redis.call('GET', KEYS[1]) if (not updt) or (tonumber(updt) < tonumber(ARGV[1])) then return redis.call('MSET', KEYS[1], ARGV[1], KEYS[2], ARGV[2]) else return redis.error_reply('data is newer on server!') end" 2 dataUpdated data 1 initVal
You will find in Lua Scripts a very powerful tool to get the most out of Redis.

How can I use ruby to generate a MySQL password hash for its sha256 format?

I am using puppet to manage my MySQL deployments. Service accounts are also managed via puppet because AWS doesn't provide the ability for me to leverage OpenLDAP as an authentication provider to RDS. I was given the requirement to use the sha256_password plugin for mysql. The puppet module I am using to manage everything, https://forge.puppet.com/puppetlabs/mysql, requires me to provide a hashed password to the user resource and the function included in the module only generates the mysql_native password. How can I use Ruby to generate the required hash? Below is the code I have so far.
require 'digest'
salt = Array.new(20){rand(256).chr}.join
hash = salt + 'Password'
rounds = 5000 # 5 iteration count * 1000 multipler per mysql code
x = 0
while x < rounds do
hash = Digest::SHA2.new(256).hexdigest(hash)
x += 1
end
h_salt = [salt].pack('H*')
b_hash = [hash[0..42]].pack('m')
h_hash = [hash].pack('H*')
value = '$A$005$' + h_salt + h_hash
print value
I can't determine if I'm encoding the salt and digest correctly. I believe I have the correct format other wise.
From https://crypto.stackexchange.com/questions/77427/whats-the-algorithm-behind-mysqls-sha256-password-hashing-scheme,
the expected format:
DELIMITER[digest_type]DELIMITER[iterations]DELIMITER[salt][digest]
It seems after reviewing the source code and others implementation of it, the salt and digest are base64 encoded HEX values. Is that correct?
Some examples I leveraged were from:
https://github.com/hashcat/hashcat/issues/2305

puppet functions exec windows command line

Currently i am trying to automate the start mode in windows server services. i tried to use puppetlabs registry but realized that the module didn't work as i expected.
Basically i have list of windows services that i need to update on each server but on some servers, the services might not exist, but puppetlabs registry will just create the new key if it's not exist which is not the expected behaviour. By right, it should work as mentioned below:
Check whether the service is in the servers or not
If it does, then update the start mode as mentioned inside the manifest/hiera
If not exist, just do nothing and skip to the next service immediately
Based from what i knew, it seems the only way to check whether the service key exist or not is by using custom function. So i already tried to write some custom function using win32/registry, but was unsuccessful by getting some error such as Win32API not supported. Another way i can think of is using the reg command line to check whether the key exist or not. Here is the puppet code functions:
module Puppet::Parser::Functions
newfunction(:check_winservice_exist, :type => :rvalue) do |args|
service_name = args[0]
unless args.length > 0 then
raise Puppet::ParseError, ("check_winservice_exist(): wrong number of arguments (#{args.length}; must be > 0)")
end
command = "reg query HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\#{service_name} /f DisplayName"
result = system command
return result
#if result == true
# return result
#else
# return result
#end
end
end
When i run the simplified ruby scripts in command line, it works and return the expected value. But when i used above scripts as puppet custom functions, it always return empty.
This is my first time to write a puppet custom functions so i am not sure what i did wrong here. Please advise whether there are another alternative that i can use to resolve the issue or maybe advise on what i did wrong on the functions script
I managed to resolve this issue by using custom facter as suggested by Matt. Just sharing the custom facter scripts that i used. It might not be perfect as i am still not really proficient in using ruby.
require 'win32/registry'
Facter.add(:winservices) do
confine :kernel => "windows"
setcode do
keyname= 'SYSTEM\CurrentControlSet\Services'
access = Win32::Registry::KEY_ALL_ACCESS
arr = []
winservices_list = []
Win32::Registry::HKEY_LOCAL_MACHINE.open(keyname, access) do |reg|
service_lists = (reg.each_key { |key, wtime| arr.push key })
arr.each do |service|
service_key = "SYSTEM\\CurrentControlSet\\Services\\#{service}"
begin
Win32::Registry::HKEY_LOCAL_MACHINE.open(service_key, access) do |reg|
value = reg['Start']
winservices_list.push service
end
rescue
end
end
winservices_list
end
end
end
And it simply works just by adding simply checking whether the service name is in the array or not
if $service_name in $facts['winservices'] {
service { "${service_name}":
provider => 'windows',
enable => $start_real,
}
}

HMAC-SHA1 in bash

Is there a bash script available to generate a HMAC-SHA1 hash?
The equivalent of the following PHP code:
hash_hmac("sha1", "value", "key", TRUE);
Parameters
true : When set to TRUE, outputs raw binary data. FALSE outputs lowercase hexits.
Thanks.
see HMAC-SHA1 in bash
In bash itself, no, it can do a lot of stuff but it also knows when to rely on external tools.
For example, the Wikipedia page provides a Python implementation which bash can call to do the grunt work for HMAC_MD5, repeated below to make this answer self-contained:
#!/usr/bin/env python
from hashlib import md5
trans_5C = "".join(chr(x ^ 0x5c) for x in xrange(256))
trans_36 = "".join(chr(x ^ 0x36) for x in xrange(256))
blocksize = md5().block_size
def hmac_md5(key, msg):
if len(key) > blocksize:
key = md5(key).digest()
key += chr(0) * (blocksize - len(key))
o_key_pad = key.translate(trans_5C)
i_key_pad = key.translate(trans_36)
return md5(o_key_pad + md5(i_key_pad + msg).digest())
if __name__ == "__main__":
h = hmac_md5("key", "The quick brown fox jumps over the lazy dog")
print h.hexdigest() # 80070713463e7749b90c2dc24911e275
(keeping in mind that Python also contains SHA1 stuff as well, see here for details on how to use HMAC with the hashlib.sha1() constructor).
Or, if you want to run the exact same code as PHP does, you could try running it with phpsh, as detailed here.

Mimic AES_ENCRYPT and AES_DECRYPT functions in Ruby

I need to mimic what MySQL does when encrypting and decrypting strings using built-in functions AES_ENCRYPT() and AES_DECRYPT().
I have read a couple of blog posts and apparently MySQL uses AES 128-bit encryption for those functions. On top of that, since this encryption requires a 16-bit key, MySQL pads the string with x0 chars (\0s) until it's 16-bit in size.
The algorithm in C from MySQL source code is spotted here.
Now I need to replicate what MySQL does in a Rails application, but every single thing I tried, doesn't work.
Here's a way to replicate the behavior I am getting:
1) Create a new Rails app
rails encryption-test
cd encryption-test
2) Create a new scaffolding
script/generate scaffold user name:string password:binary
3) Edit your config/database.yml and add a test MySQL database
development:
adapter: mysql
host: localhost
database: test
user: <<user>>
password: <<password>>
4) Run the migration
rake db:migrate
5) Enter console, create an user and update its password from MySQL query
script/console
Loading development environment (Rails 2.2.2)
>> User.create(:name => "John Doe")
>> key = "82pjd12398JKBSDIGUSisahdoahOUASDHsdapdjqwjeASIduAsdh078asdASD087asdADSsdjhA7809asdajhADSs"
>> ActiveRecord::Base.connection.execute("UPDATE users SET password = AES_ENCRYPT('password', '#{key}') WHERE name='John Doe'")
That's where I got stuck. If I attempt to decrypt it, using MySQL it works:
>> loaded_user = User.find_by_sql("SELECT AES_DECRYPT(password, '#{key}') AS password FROM users WHERE id=1").first
>> loaded_user['password']
=> "password"
However if I attempt to use OpenSSL library, there's no way I can make it work:
cipher = OpenSSL::Cipher::Cipher.new("AES-128-ECB")
cipher.padding = 0
cipher.key = key
cipher.decrypt
user = User.find(1)
cipher.update(user.password) << cipher.final #=> "########gf####\027\227"
I have tried padding the key:
desired_length = 16 * ((key.length / 16) + 1)
padded_key = key + "\0" * (desired_length - key.length)
cipher = OpenSSL::Cipher::Cipher.new("AES-128-ECB")
cipher.key = key
cipher.decrypt
user = User.find(1)
cipher.update(user.password) << cipher.final #=> ""|\e\261\205:\032s\273\242\030\261\272P##"
But it really doesn't work.
Does anyone have a clue on how can I mimic the MySQL AES_ENCRYPT() and AES_DECRYPT() functions behavior in Ruby?
Thanks!
For future reference:
According to the blog post I sent before, here's how MySQL works with
the key you provide AES_ENCRYPT / DECRYPT:
"The algorithm just creates a 16 byte
buffer set to all zero, then loops
through all the characters of the
string you provide and does an
assignment with bitwise OR between the
two values. If we iterate until we
hit the end of the 16 byte buffer, we
just start over from the beginning
doing ^=. For strings shorter than 16
characters, we stop at the end of the
string."
I don't know if you can read C, but here's the mentioned snippet:
http://pastie.org/425161
Specially this part:
bzero((char*) rkey,AES_KEY_LENGTH/8); /* Set initial key */
for (ptr= rkey, sptr= key; sptr < key_end; ptr++,sptr++)
{
if (ptr == rkey_end)
ptr= rkey; /* Just loop over tmp_key until we used all key */
*ptr^= (uint8) *sptr;
}
So I came up with this method (with a help from Rob Biedenharn, from ruby forum):
def mysql_key(key)
final_key = "\0" * 16
key.length.times do |i|
final_key[i%16] ^= key[i]
end
final_key
end
That, given a string returns the key MySQL uses when encrypting and decrypting. So all you need now is:
def aes(m,k,t)
(aes = OpenSSL::Cipher::AES128.new("ECB").send(m)).key = k
aes.update(t) << aes.final
end
def encrypt(key, text)
aes(:encrypt, key, text)
end
def decrypt(key, text)
aes(:decrypt, key, text)
end
To use openssl lib, built into ruby, and then you can make the two "final" methods:
def mysql_encrypt(s, key)
encrypt(mysql_key(key), s)
end
def mysql_decrypt(s, key)
decrypt(mysql_key(key), s)
end
And you're set! Also, complete code can be found in this Gist:
http://gist.github.com/84093
:-)
Generally you don't want to pad the key, you pad/unpad the data to be encrypted/decrypted. That could be another source of problems. I suggest using test data of a complete number of blocks to eliminate this possibility.
Also, I suspect the key for the OpenSSL API requires a "literal" key, not an ASCII representation of the key as you have in your code.
Given the paucity of the OpenSSL ruby docs and if you speak a little Java, you may want to prototype in JRuby with the BouncyCastle provider - this is something that I've done to good effect when working with TwoFish (not present in OpenSSL API).
EDIT: I re-read your comment about padding the key. You have some bits/bytes confusion in your question, and I'm not sure how this applies in any case since your posted key is 89 characters (712 bits) in length. Perhaps you should try with a 128 bit key/password to eliminate this padding phenomenon?
Incidentally, MySQL devs should be spanked for weak crypto, there are better ways to stretch passwords than by simply padding with zero bytes :(
If you don't mind using an openssl implementation attr_encrypted is a gem that will allow drop-in encryption on most classes, ActiveRecord or not. It unfortunately will not be compatible with MySQL's AES_EN/DECRYPT functions though.

Resources