I recently came across a situation where I absolutely needed to use the method OpenSSL::PKey::RSA#params. However, the doc says the following:
THIS METHOD IS INSECURE, PRIVATE INFORMATION CAN LEAK OUT!!!
...
Don’t use :-)) (It’s up to you)
What does this mean? How is the private key normally protected within the instance of the RSA key and how is this different from any regular object?
Can I prevent information from leaking by doing something like this, where the method is only accessed within a lambda:
private_key = OpenSSL::PKey::RSA.generate(2048)
save_private = lambda do
key = OpenSSL::Digest::SHA512.new.digest("password")
aes = OpenSSL::Cipher.new("AES-256-CFB")
iv = OpenSSL::Random.random_bytes(aes.iv_len)
aes.encrypt
aes.key, aes.iv = key, iv
aes.update(private_key.params.to_s) + aes.final
end
private_enc, save_private = save_private.call, nil
Also, if this security problem has anything to do with variables lingering in memory awaiting GC, can forcing garbage collection make things more secure?
GC.start
Thanks in advance to anybody who can clear this up.
It seems to give away information of the private key. The key components need to be available to perform any signing operation or decryption so normally the key information is in memory in the clear. Obviously if you retrieve it you must make sure that you keep it safe. I presume that this is where the warning comes in.
You can do all kinds of things like encrypting the private key parameters, but then you get to a point where you have to store the decryption key. Basically this will end up being impossible to solve without an external system (or a person keeping a password).
Related
I have a SecTrustRef object from the system that I'd like to evaluate myself. Just calling SecTrustEvaluateAsync will be sufficient for this job. The problem is, I must evaluate it in a different process as only this other process has access to the keychains where the CA certificates are stored that may cause evaluation to succeed.
The two processes have an IPC link that allows me to exchange arbitrary byte data between them but I don't see any way to easily serialize a SecTrustRef into byte data and deserialize that data back to an object at the other process. There doesn't seem to be a persistent storage mechanism for SecTrustRef.
So am I overlooking something important here, or do I really have to get all the certs (SecTrustGetCertificateAtIndex) and all the policies (SecTrustCopyPolicies) and serialize these myself?
And if so, how would I serialize a policy?
For the certificate (SecCertificateRef) it's rather easy, I just call SecCertificateCopyData and later on SecCertificateCreateWithData.
But for policies I can only call SecPolicyCopyProperties on one side and later on SecPolicyCreateWithProperties, however the later one requires a 2nd parameter, a policyIdentifier and I see no way to get that value from an existing policy. What am I missing?
Reading through the source of the Security framework, I finally figured it out how to copy a SecPolicyRef:
SecPolicyCreateWithProperties wants what it calls a "policyIdentifier". It's a constant like kSecPolicyAppleIPsec.
This does not get stored directly by the function, it's comparing the value and calling dedicated internal "initializers" (like SecPolicyCreateIPsec).
These in turn call SecPolicyCreate (which is private). They end up passing the same identifier value that you passed to SecPolicyCreateWithProperties.
And this value then gets stored as-is in the _oid field!
The identifier is actually the OID. You can get it either via SecPolicyCopyProperties(policy) (stored in the dictionary with key kSecPolicyOid) or via SecPolicyGetOID (but that returns it as an inconvenient CSSM_OID). Some of those specialized initializers also use values from the properties dictionary passed to SecPolicyCreateWithProperties, those should be present in the copied properties dictionary already.
So this gives us:
Serialization:
CFDictionaryRef createSerializedPolicy(SecPolicyRef policy) {
// Already contains all the information needed.
return SecPolicyCopyProperties(policy);
}
Deserialization:
SecPolicyRef createDeserializedPolicy (CFDictionaryRef serialized) {
CFStringRef oid = CFDictionaryGetValue(serialized, kSecPolicyOid);
if (oid == NULL || CFGetTypeID(oid) != CFStringGetTypeID()) {
return NULL;
}
return SecPolicyCreateWithProperties(oid, serialized);
}
To reproduce the original SecTrustRef as closely as possible, the anchors need to be copied as well. There is an internal variable _anchorsOnly which is set to true once you set anchors. Unfortunately, there is no way to query this value and I've seen it being false in trusts passed by NSURLSession, for example. No idea yet on how to get this value in a public way.
Another problematic bit are the exceptions: if _exceptions is NULL but you query them via SecTrustCopyExceptions(trust), you do get data! And if you assign that to the deserialized trust via SecTrustSetExceptions(trust, exceptions) you suddenly end up with exceptions that were not there before and can change the evaluation result! (I've seen those suddenly appearing exceptions lead to an evaluation result of "proceed" instead of "recoverable trust failure").
I am trying to use the bitcoin-ruby gem to create a new address for payment transactions from my public Bitcoin Address.
I am able to use the pubkey_to_address method to do this. However, each time I run the method the resulting address, payment_address, is the same. Services such as blockchain.info return a different address each time which is more consistent with my requirement.
Bitcoin-ruby github reference
https://github.com/lian/bitcoin-ruby/blob/master/lib/bitcoin.rb#L128
My Code is below
require 'bitcoin'
ORIGIN_ADDRESS = "1BjxMfaBpsXu8AnAA44TTgopWuE6QamvCQ"
payment_address = Bitcoin::pubkey_to_address(ORIGIN_ADDRESS)
puts payment_address
# => "171GYkox1rWqNf8skyK2Aw9EAnVJ1wPwKf"
With #Thilo's feedback I now understand this. The services that I had been using were abstracting the fact that the were generating new "receiver" address with new private key that automatically forwards back to the Bitcoin address I provided them when a transaction was confirmed on block chain.
As Thilo points out, I should use new pub/priv key for each transaction and keep the priv key offline if at all possible. This priv key can then be used for future Bitcoin transactions against funds paid to the public address.
I'm getting there.. thanks
I had a similar issue to what you had. Try doing this:
def gen_address
ORIGIN_ADDRESS = "1BjxMfaBpsXu8AnAA44TTgopWuE6QamvCQ"
return Bitcoin::pubkey_to_address(ORIGIN_ADDRESS)
end
puts gen_address()
(There might be a syntax error, but the code should be something like this).
Let me know if this doesnt work.
I'm using Net::SSH to automate access to remove hosts from a ruby program, using key authentication. The program does not dictate where the user should put the private key, instead relying on the user's SSH agent to provide the required keys (as it should).
The problem is if the required private key is not available, the connection will fail - and this may happen a long way into the program (the SSH connection is one of the last things we do after doing a lot of other - not easily reversible - operations).
Supposed that I know what private key the user should have (as specified by the key fingerprint), how can I do this check from ruby - other then execute ssh-add -l and grepping the output?
I've looked at Net::SSH KeyFactory class, but it only lets you load private keys if you know the name of the file in which they are stored.
I figured it out - Net::SSH::Authentication::KeyManager has what I need:
hasidentity = false
Net::SSH::Authentication::KeyManager.new(nil?).each_identity do |i|
hasidentity |= i.fingerprint == 'my:ke:ys:fi:ng:er:pr:in:t'
end
KeyManager also has a collection called identities, though from what I understand, that holds only keys loaded directly into Net::SSH, while each_identity iterates over all available identities, including those available from an agent.
I have an RSA public key, some data and a signature of that data. I need to verify the signature. However, the signature is not of a digest of the data, but of the entire data. (The data itself is only 16 bytes, so the signer doesn't bother to hash the data before signing it.) I can verify the signature in C by specifying a NULL engine when initializing the context:
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(verify_key, NULL);
However, I have been unable to find an equivalent in Ruby's OpenSSL::PKey::PKey verify method. That method requires a Digest object, and there is no Digest that I can find that doesn't actually hash but just returns the data as-is. I tried creating my own Digest subclass, but I don't believe that can work, since the underlying OpenSSL library won't know about the existence of a custom digest type.
Am I stuck, or is there a way to solve this problem given that I cannot modify the code run by the signer?
Summarizing the answer from the comments in order to remove this question from the "Unanswered" filter...
owlstead:
Have you tried to find a function like public_decrypt? It may work, as normally you should not encryption with a private key and decrypt with a public key. With a bit of luck it will accept the signature version of PKCS#1 padding (note that the padding used for encryption and signing is different in PKCS#1).
Wammer:
Of course - decrypting the signature with the public key and verifying that it matches the data works fine. So far this is working fine with the standard PKCS#1 padding, but I'll do some more research to see if the differing encryption and signing paddings are a problem in practice. Thanks.
owlstead:
After a decrypt and validation of the padding, all that is left is a (if possible, secure) compare. So that would replace the verification function pretty well. Most of the security is in the modular arithmetic and padding.
This feels like it should be dead simple, yet I'm not having any luck.
The scenario is this: I have a public *.asc key file. I want to use this file (not my personal keyring) to encrypt data on a server, so that I can decrypt it locally with a secret key.
From the command line I can achieve this using gpg, but I'd prefer to use a Ruby library that isn't just a wrapper around the CLI (i.e., presumably one that provides bindings to the C library). I've looked at the GPGME and OpenPGP gems and haven't been able to figure out how to use them. The documentation (especially for OpenPGP) is quite sparse.
Here, for example, is something I've tried using GPGME, without any luck:
key = GPGME::Data.new(File.open(path_to_file))
data = GPGME::Data.new("I want to encrypt this string.")
# Raises GPGME::Error::InvalidValue
GPGME::Ctx.new do |ctx|
e = ctx.encrypt(key, data)
end
Has anyone been through this already? Surely this can't be that complicated?
I believe I've now got this figured out. It was actually just a few simple pieces I was missing:
Initializing the GPGME::Ctx object with a keylist_mode of GPGME::KEYLIST_MODE_EXTERN.
Importing the public key file using GPGME::Ctx#import.
Using GPGME::Crypto#encrypt to perform the encryption and specifying the correct recipient.
So my solution now looks like this:
key = GPGME::Data.new(File.open(path_to_file))
data = GPGME::Data.new("I want to encrypt this string.")
GPGME::Ctx.new(GPGME::KEYLIST_MODE_EXTERN) do |ctx|
ctx.import(key)
crypto = GPGME::Crypto.new(:armor => true, :always_trust => true)
e = crypto.encrypt(data, :recipients => "recipient#domain.com")
end