How can I encrypt a string with MD5 in Rails 3.0 ?
pass = MD5.hexdigest(pass) in a model yields uninitialized constant MyModel::MD5
You can use Digest::MD5 from the Ruby standard library for this.
irb(main):001:0> require 'digest/md5'
=> true
irb(main):002:0> Digest::MD5.hexdigest('foobar')
=> "3858f62230ac3c915f300c664312c63f"
And one more thing: MD5 is a hash algorithm. You don't "encrypt" anything with a hash algorithm.
Related
I have a YAML config file where I want to include specific ruby class/module constants instead of the actual value.
For example, instead of putting "loglevel: 0" in the config file, I want "loglevel: Logger::DEBUG".
Is there a way to have YAML decode or resolve a class or module constant like Logger::DEBUG?
This is what I've been playing with, but looking at the psych ruby code, I don't see anything that might support this.
config.yml
loglevel: !ruby/class:fixnum Logger::DEBUG
In irb
irb> require 'logger'
irb> config = YAML.load_file('config.yml')
config['loglevel'] contains "Logger::DEBUG" as a String instead of the actual value.
I can do an eval on it like so:
irb> p eval config['loglevel']
0
==> 0
I'm just wondering if there's a way to have YAML eval it? I'm okay with doing it in my code after doing a YAML load, but I wanted to make sure I left no stone unturned in my, what has turned into a lengthy, quest ;-).
Not sure of a YAML way, but best not to use eval...
In Ruby 2+
Object.const_get 'Logger::DEBUG'
Or the old school
def const_lookup const_name
const_name.split('::').inject(Object) do |rec, name|
rec.const_get(name)
end
end
const_lookup 'Logger::DEBUG'
Looks like you can do it for classes/modules but not their constants
2.0.0-p247 :046 > YAML.load("!ruby/class 'String'")
=> String
2.0.0-p247 :047 > YAML.load("!ruby/class 'String'").class
=> Class
2.0.0-p247 :065 > YAML.load("!ruby/class 'Logger'")
=> Logger
I'm currently using XmlSimple in Ruby to convert XML to a hash using the xml_in method. Everything is really nice, except for the fact that the resulting hash keys are all lowercase, whereas the XML element names were mixed-case.
Here's an example:
hash = XmlSimple.xml_in( xml_string, { 'KeyAttr' => 'name',
'ForceArray' => false,
'NoAttr' => true,
'KeyToSymbol' => true,
'SuppressEmpty' => "" } )
So, for example, this xml:
<aclEntry>
<aclEntryId>Stuff here</aclEntryId>
<principalName>Stuff here</principalName>
</aclEntry>
results in this hash:
{ :aclentryid => "Stuff Here", :principalname => "Stuff here" }
I've looked over the documentation for XmlSimple, and didn't see any option that indicated it could maintain mixed-case in the document-to-hash conversion.
Is there any way to use XmlSimple to maintain case sensitivity in the resulting hash? If not, is there an alternative Ruby XML parser that can generate a hash that maintains case-sensitivity like this?
Combination of Nokogiri and Activesupport will help.
require 'active_support/core_ext/hash/conversions'
require 'nokogiri'
require 'pp'
xml_doc = Nokogiri::XML("<aclEntry><aclEntryId>Stuff here</aclEntryId><principalName>Stuff here</principalName></aclEntry>")
h = Hash.from_xml(xml_doc.to_s).symbolize_keys
pp h #=> {:aclEntry=>{"aclEntryId"=>"Stuff here", "principalName"=>"Stuff here"}}
You can also do the same with ReXML and Activesupport
require 'rexml/document'
require 'pp'
include REXML
require 'active_support/core_ext/hash/conversions'
xmldoc = Document.new("<aclEntry><aclEntryId>Stuff here</aclEntryId><principalName>Stuff here</principalName></aclEntry>")
h = Hash.from_xml(xmldoc.to_s).symbolize_keys
pp h #=> {:aclEntry=>{"aclEntryId"=>"Stuff here", "principalName"=>"Stuff here"}}
EDIT : Having done a bit of reading it turns out that passing some options to SimpleXML produces the result you want, except that it doesn't symbolize the hash keys but that's a different issue.
require 'xmlsimple'
require 'pp'
xml_str = <<XML_STR
<aclEntry>
<aclEntryId>Stuff here</aclEntryId>
<principalName>Stuff here</principalName>
</aclEntry>
XML_STR
result = XmlSimple.xml_in xml_str, { 'ForceArray' => false, 'AttrPrefix' => true, 'KeyToSymbol' => true }
pp result # =>{:principalName=>"Stuff here", :aclEntryId=>"Stuff here"}
When using Tempfile Ruby is creating a file with a thread-safe and inter-process-safe name. I only need a file name in that way.
I was wondering if there is a more straight forward approach way than:
t = Tempfile.new(['fleischwurst', '.png'])
temp_path = t.path
t.close
t.unlink
Dir::Tmpname.create
You could use Dir::Tmpname.create. It figures out what temporary directory to use (unless you pass it a directory). It's a little ugly to use given that it expects a block:
require 'tmpdir'
# => true
Dir::Tmpname.create(['prefix-', '.ext']) {}
# => "/tmp/prefix-20190827-1-87n9iu.ext"
Dir::Tmpname.create(['prefix-', '.ext'], '/my/custom/directory') {}
# => "/my/custom/directory/prefix-20190827-1-11x2u0h.ext"
The block is there for code to test if the file exists and raise an Errno::EEXIST so that a new name can be generated with incrementing value appended on the end.
The Rails Solution
The solution implemented by Ruby on Rails is short and similar to the solution originally implemented in Ruby:
require 'tmpdir'
# => true
File.join(Dir.tmpdir, "YOUR_PREFIX-#{Time.now.strftime("%Y%m%d")}-#{$$}-#{rand(0x100000000).to_s(36)}-YOUR_SUFFIX")
=> "/tmp/YOUR_PREFIX-20190827-1-wyouwg-YOUR_SUFFIX"
File.join(Dir.tmpdir, "YOUR_PREFIX-#{Time.now.strftime("%Y%m%d")}-#{$$}-#{rand(0x100000000).to_s(36)}-YOUR_SUFFIX")
=> "/tmp/YOUR_PREFIX-20190827-1-140far-YOUR_SUFFIX"
Dir::Tmpname.make_tmpname (Ruby 2.5.0 and earlier)
Dir::Tmpname.make_tmpname was removed in Ruby 2.5.0. Prior to Ruby 2.4.4 it could accept a directory path as a prefix, but as of Ruby 2.4.4, directory separators are removed.
Digging in tempfile.rb you'll notice that Tempfile includes Dir::Tmpname. Inside you'll find make_tmpname which does what you ask for.
require 'tmpdir'
# => true
File.join(Dir.tmpdir, Dir::Tmpname.make_tmpname("prefix-", nil))
# => "/tmp/prefix-20190827-1-dfhvld"
File.join(Dir.tmpdir, Dir::Tmpname.make_tmpname(["prefix-", ".ext"], nil))
# => "/tmp/prefix-20190827-1-19zjck1.ext"
File.join(Dir.tmpdir, Dir::Tmpname.make_tmpname(["prefix-", ".ext"], "suffix"))
# => "/tmp/prefix-20190827-1-f5ipo7-suffix.ext"
Since Dir::Tmpname.make_tmpname was removed in Ruby 2.5.0, this one falls back to using SecureRandom:
require "tmpdir"
def generate_temp_filename(ext=".png")
filename = begin
Dir::Tmpname.make_tmpname(["x", ext], nil)
rescue NoMethodError
require "securerandom"
"#{SecureRandom.urlsafe_base64}#{ext}"
end
File.join(Dir.tmpdir, filename)
end
Since you only need the filename, what about using the SecureRandom for that:
require 'securerandom'
filename = "#{SecureRandom.hex(6)}.png" #=> "0f04dd94addf.png"
You can also use SecureRandom.alphanumeric
I found the Dir:Tmpname solution did not work for me. When evaluating this:
Dir::Tmpname.make_tmpname "/tmp/blob", nil
Under MRI Ruby 1.9.3p194 I get:
uninitialized constant Dir::Tmpname (NameError)
Under JRuby 1.7.5 (1.9.3p393) I get:
NameError: uninitialized constant Dir::Tmpname
You might try something like this:
def temp_name(file_name='', ext='', dir=nil)
id = Thread.current.hash * Time.now.to_i % 2**32
name = "%s%d.%s" % [file_name, id, ext]
dir ? File.join(dir, name) : name
end
I'm using Ruby to try and encrypt a string which will be stored in a database and read/decrypted by a Flash/Actionscript app.
The app uses this blowfish implementation.
I have tried both the openssl and crypt/blowfish methods of creating a compatible string. Neither match each other and neither matches what the Flash app expects.
Where do I start in terms of getting this to work?
irb(main):001:0> require 'openssl'
=> true
irb(main):002:0> require 'crypt/blowfish'
=> true
irb(main):007:0> require 'base64'
=> true
irb(main):003:0> key = "foo"
=> "foo"
irb(main):004:0> plain = "some string"
=> "some string"
irb(main):005:0> blowfish = Crypt::Blowfish.new(key)
=>
irb(main):006:0> enc = blowfish.encrypt_block(plain)
=> "\xF5\xAFB\x12=\xB9\xDB\f"
irb(main):008:0> Base64.encode64(enc)
=> "9a9CEj252ww=\n"
# Now, openssl version
irb(main):009:0> cipher = OpenSSL::Cipher::Cipher.new('bf-cbc').send(:encrypt)
=> #<OpenSSL::Cipher::Cipher:0x00000000f26430>
irb(main):010:0> cipher.key = Digest::SHA256.digest(key)
=> ",&\xB4kh\xFF\xC6\x8F\xF9\x9BE<\x1D0A4\x13B-pd\x83\xBF\xA0\xF9\x8A^\x88bf\xE7\xAE"
irb(main):011:0> enc = cipher.update(plain) << cipher.final
=> "m<\xDB\xC1B\x02p\xB0\xD6\xD0\xA4\xE8XyY\x99"
irb(main):012:0> Base64.encode64(enc)
=> "bTzbwUICcLDW0KToWHlZmQ==\n"
EDIT
Here's what we're doing in AS3 (with the blowfish code mentioned above):
import com.lassieadventurestudio.Blowfish;
import fl.controls.Button;
import fl.controls.TextInput;
import flash.events.MouseEvent;
var $key:String = "foo";
BTN_Submit.label = "Encrypt";
BTN_Submit.addEventListener(MouseEvent.CLICK, onSubmit);
function onSubmit(event:MouseEvent):void
{
trace("INP_Pass.text, ", INP_Pass.text);
var $encryption:String = Blowfish.encrypt(INP_Pass.text, $key);
TXT_Output.text = $encryption;
}
BTN_Decrypt.label = "Decrypt";
BTN_Decrypt.addEventListener(MouseEvent.CLICK, decrypt);
function decrypt(event:MouseEvent):void
{
TXT_Output2.text = Blowfish.decrypt(TXT_Output.text, $key);
}
The problem is that both ways you tried do use CBC mode, but the AS3 example you linked to is using ECB mode.
You can achieve the same using this:
cipher = OpenSSL::Cipher.new('bf-ecb')
cipher.encrypt
cipher.key = key
enc = cipher.update(plain) << cipher.final
Be warned though, this is not a good encryption scheme at all for several reasons (ECB, Blowfish key length, password used directly as key...), as was written in the article, it will only hold off prying eyes, but this will not pose an obstacle to someone who is dedicated about it.
Edit:
I looked at the AS3 implementation, but unfortunately I wasn't able to reproduce the example results given there. But I am confident that the Blowfish implementation from the blog is bad, you shouldn't use it. There they take plain passwords for keys, and to make things worse, they Base64-decode them first to get raw bytes, thereby effectively decreasing the already bad entropy again by a factor of 3/4.
Ruby OpenSSL's Blowfish implementation takes 16 byte keys, so you won't be lucky in reproducing the results with shorter keys. I would recommend to you to do the following:
Use AES instead of Blowfish. While Blowfish has never been "broken", its effective security of 56 bits can be brute-forced.
Don't use passwords as keys. Use cryptographically secure random bytes. An easy way to do this in Ruby for example is:
key = cipher.random_key
You may want to find something similar in AS3.
Don't use ECB mode. Use CBC mode or, if available with your OpenSSL version (requires >=1.0.0), even better, use CTR mode.
You might want to look at the Cipher docs for more advice on achieving something that may be considered secure.
SHA Hash functions
require 'digest/sha1'
Digest::SHA1.hexdigest 'foo'
For a Base64 encoded hash, to validated an Oauth signature, I used
require 'base64'
require 'hmac-sha1'
Base64.encode64((HMAC::SHA1.new('key') << 'base').digest).strip
I created a helper gem which is a simple wrapper around some sha1 code
require 'rickshaw'
> Rickshaw::SHA1.hash('LICENSE.txt')
=> "4659d94e7082a65ca39e7b6725094f08a413250a"
> "hello world".to_sha1
=> "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"
Where 'serialize' is some user function defined elsewhere.
def generateKey(data)
return Digest::SHA1.hexdigest ("#{serialize(data)}")
end