Highline padding inserted password with random number of * - ruby

I have a ruby script that ask for password using highline/import:
ask("Enter your password: ") { |q| q.echo = "*" }
I want to add a random number of * to the output once the user finishes to input their password. That's because the output is captured and I don't want to reveal the length of the password. As a requirement I can't disable the echo.

You can just multiply '*' by a random value. Import SecureRandom:
require 'securerandom'
Then in that block:
q.echo = '*' * SecureRandom.rand(5..15)

Related

Ruby openssl encryption with DES-CBC incorrect result

I am trying to replicate the encryption result from here in Ruby using OpenSSL: https://emvlab.org/descalc/?key=18074F7ADD44C903&iv=18074F7ADD44C903&input=4E5A56564F4C563230313641454E5300&mode=cbc&action=Encrypt&output=25C843BA5C043FFFB50F76E43A211F8D
Original string = "NZVVOLV2016AENS"
String converted to hexadecimal = "4e5a56564f4c563230313641454e53"
iv = "18074F7ADD44C903"
key = "18074F7ADD44C903"
Expected result = "9B699B4C59F1444E8D37806FA9D15F81"
Here is my ruby code:
require 'openssl'
require "base64"
include Base64
iv = "08074F7ADD44C903"
cipher = "08074F7ADD44C903"
def encode(string)
puts "Attempting encryption - Input: #{string}"
encrypt = OpenSSL::Cipher.new('DES-CBC')
encrypt.encrypt
encrypt.key = ["18074F7ADD44C903"].pack('H*') #.scan(/../).map{|b|b.hex}.pack('c*')
encrypt.iv = ["18074F7ADD44C903"].pack('H*')
result = encrypt.update(string) + encrypt.final
puts "Raw output: #{result.inspect}"
unpacked = result.unpack('H*')[0]
puts "Encrypted key is: #{unpacked}"
puts "Encrypted Should be: 9B699B4C59F1444E8D37806FA9D15F81"
return unpacked
end
res = encode("NZVVOLV2016AENS")
Output:
Encrypted key is: 9b699b4c59f1444ea723ab91e89c023a
Encrypted Should be: 9B699B4C59F1444E8D37806FA9D15F81
Interestingly, the first half of the result is correct, and the last 16 digits are incorrect.
The web site uses Zero padding by default, while the Ruby code uses PKCS#7 padding by default.
Ruby does not seem to support Zero padding, so disable the default padding and implement Zero padding yourself.
Zero padding pads to the next full block size with 0x00 values. The block size for DES is 8 bytes. If the last block of the plaintext is already filled, no padding is done:
def zeroPad(string, blocksize)
len = string.bytes.length
padLen = (blocksize - len % blocksize) % blocksize
string += "\0" * padLen
return string
end
In the encode() function (which should better be called encrypt() function) the following lines must be added before encryption:
encrypt.padding = 0 # disable PKCS#7 padding
string = zeroPad(string, 8) # enable Zero padding
The modified Ruby code then gives the same ciphertext as the web site.
Note that DES is insecure, also it' s insecure to use the key as IV (as well as a static IV). Furthermore, Zero padding is unreliable in contrast to PKCS#7 padding.

Login System - Python

I'm not that great at programming and so that is why I am here asking help. I am creating a login system for my Hotel Booking System but I am experiencing some problems with it.
This is what I have done for the Login Sytem through the help someone else's code. Link: Python Login and Register System using text files
def get_existing_users():
with open("login.txt", "r" ) as f:
for line in f.readlines():
# This expects each line of a file to be (name, pass) seperated by whitespace
username, password = line.split(',')
yield username, password
def is_authorized(username, password):
return any((user == (username, password) for user in get_existing_users()))
def user_exists(username):
return any((usr_name == username) for usr_name, _ in get_existing_users())
# above is equivalent of:
#
# for usr_name, _ in get_existing_users():
# if usr_name == username:
# return True
# return False
def ask_user_credentials():
count = 0
while count < 3:
username = input("Enter Username: ")
password = input("Enter a Password: ")
if is_authorized(username, password):
print ("Welcome to the Majestic Hotel Booking system ") + username
MainMenu()
if user_exists(username):
print("The password entered is wrong, please try again")
print("The username entered is wrong, please try again")
count = count + 1
def getdetails():
forename = input("Enter forename: ")
surname = input("Enter Surname: ")
year = input("Enter year you are born: ")
if year <= '2004':
print("You are old enough to register yourself")
username = forename[0]+surname[0:3]+year[3:4]
print("Username: ", username)
password = input("Enter a password: ")
file = open("login.txt","a")
file.write(username + "," + password + "\n")
file.close()
MainMenu()
else:
print("Sorry you are not old enough to register by yourself") enter code here
if account == "No":
print(getdetails())
if account == "Yes":
print(ask_user_credentials())
After creating or logging in to the account, the program will direct them to the main menu that is why you will see MainMenu() in the code.
I created an account, as shown below:
WELCOME TO THE MAJESTIC HOTEL lOGIN SYSTEM
************************************************
Do you have an account? Yes or No: No
Enter forename: Rose
Enter Surname: Moon
Enter year you are born: 2000
You are old enough to register yourself
Username: RMoo0
Enter a password: door
This was then saved in a text file called login.txt, like this:
RMoo0,door
However, although I created an account and it is saved into the text file but the output says this:
WELCOME TO THE MAJESTIC HOTEL lOGIN SYSTEM
************************************************
Do you have an account? Yes or No: Yes
Enter Username: RMoo0
Enter a Password: door
The password entered is wrong, please try again
The username entered is wrong, please try again
Enter Username:
Can someone please help me out and explain the solution in a way that I will understand it.
f.readlines() gives each line of txt file as :
line1\n
line2\n
.
.
.
So ,when you try to get username, password by split(",") , it look like this
("user1", "password1\n")
("user2", "password2\n")
..
Before splitting line with "," right strip each line with rstrip("\n")
def get_existing_users():
with open("login.txt", "r" ) as f:
for line in f.readlines():
username, password = line.rstrip("\n").split(',') #used rstrip here to remove the right ending "\n"
yield username, password
When addressing this kind of problem your should take into account several aspects like for example escaping your separators (of course, if you hash your passwords this isn't necessary) and not utilizing white spaces, a very good approach like linux passwd file is to add separator at the end of line to avoid different EOL terminators like \r, \n or \r\n
for Example:
def get_existing_users():
"""
This expects each line of a file to be:
(start of line)name,pass,(end of line)
"""
with open("login.txt", "r" ) as f:
for line in f.readlines():
user = line.split(',')
yield user[0], user[1]

Problem matching amounts with PaypalExpressGateway.setup_authorization

I'm using ruby client with activemerchant to create call for Paypal sandbox API. Script is being called from command line, so variables are filled with command line parameters. Here's the code sample:
login = ARGV[0]
password = ARGV[1]
signature = ARGV[2]
ip = ARGV[3]
subtotal = ARGV[4]
shipping = ARGV[5]
handling = ARGV[6]
tax = ARGV[7]
currency = ARGV[8]
return_url = ARGV[9]
cancel_return_url = ARGV[10]
allow_guest_checkout = ARGV[11]
items = JSON.parse(ARGV[12])
ActiveMerchant::Billing::Base.mode = :test
paypal_options = {
login: login,
password: password,
signature: signature
}
gateway = ActiveMerchant::Billing::PaypalExpressGateway.new(paypal_options)
setup_hash = {
ip: ip,
items: items,
subtotal: Integer(subtotal),
shipping: Integer(shipping),
handling: Integer(handling),
tax: Integer(tax),
currency: currency,
return_url: return_url,
cancel_return_url: cancel_return_url,
allow_guest_checkout: allow_guest_checkout
}
amount = subtotal.to_i + shipping.to_i + handling.to_i + tax.to_i
puts "amount: " + amount.to_s
puts "items: " + items.to_s
response = gateway.setup_authorization(amount, setup_hash)
if !(response.success?)
puts response.message.to_s
end
And here's what I get in console:
amount: 10000
items: [{"name"=>"sample", "description"=>"desc", "quantity"=>1, "amount"=>10000}]
The totals of the cart item amounts do not match order amounts.
So, how come 10000 in amount doesn't match 10000 in items?
After long and boring debugging I found out the following:
internal hash items should be [:{name=>"sample", :description=>"desc", :quantity=>1, :amount=>10000}] rather than [{"name"=>"sample", "description"=>"desc", "quantity"=>1, "amount"=>10000}] in example above.
So, I've changed JSON parser to nice_hash and with items = ARGV[12].json it works like a charm.

How to extract the IV vector generated by encrypt method from encrypted_strings

I'm having troubles to extract the IV generated with the encrypt method from encrypted_strings library for a specific password I provide. From the documentation, I see that this method generates a key and iv based on a password using a C library that calls the same method as openssl to generate the key and iv: EVP_BytesToKey.
What I'm trying to do is to be able to print the IV for any password I specify so I can port the encryption to another language.
Can you think of any method to extract/print this IV vector from a password?
These are the details of the algorithm, mode and padding this library uses:
ALGO: DES-EDE3
MODE: CBC
PADDING: PKCS5
The ruby script below prints out the encrypted message but no clue which iv was used.
#!/usr/bin/ruby
require 'encrypted_strings'
data = 'Whackabad'
password = 'bAJLyifeUJUBFWdHzVbykfDmPHtLKLMzViHW9aHGmyTLD8hGYZ'
encrypted_data = data.encrypt(:symmetric, :password => password)
printf "Data: #{data}\n"
printf "Encrypted Data: #{encrypted_data}"
I tried to use openssl as it allows me to print the iv and key generated using -p option but it uses a PKCS7 padding instead of PKCS5. So if I run the command below, doesn't print the same encrypted string as the ruby code above.
echo -n 'Whackabad' | openssl enc -des-ede3-cbc -nosalt -a -k bAJLyifeUJUBFWdHzVbykfDmPHtLKLMzViHW9aHGmyTLD8hGYZ
NOTE:
-a: base64 encode, -k: password, and echo -n: removes the new line from the string so its exactly the same size as the ruby in string.
If I add -nopad option, I don't know how to pad the output to get exactly the same encrypted result.
Any help would be much appreciated
PKCS7 padding is basically the same as PKCS5. The reason you get a different result on the command line is that it only uses a single hash iteration, where the function used by encrypted_strings does 2048 iterations by default.
The function used, EVP_BytesToKey is described in the OpenSSL wiki, which include details of the algorithm. Reproducing it in Ruby might look something like this (using MD5 and 2048 iterations):
def hash(d, count)
count.times do
d = OpenSSL::Digest.digest('md5', d)
end
d
end
password = 'bAJLyifeUJUBFWdHzVbykfDmPHtLKLMzViHW9aHGmyTLD8hGYZ'
bytes = ''
last = ''
# For des-ede3-cbc, 24 byte key + 8 byte IV = 32 bytes.
while bytes.length < 32
last = hash(last + password, 2048)
bytes << last
end
key = bytes[0...24]
iv = bytes[24..-1]
You can use these values to decrypt the result of your code (add require 'base64' first):
# This is the result of your code:
encrypted_data = "AEsDXVcgh2jsTjlDgh+REg=="
# enrypted_strings produces base64 encoded results, so we decode first
encrypted_data = Base64.decode64(encrypted_data)
cipher = OpenSSL::Cipher.new('des-ede3-cbc')
cipher.decrypt
cipher.key = key
cipher.iv = iv
plain = cipher.update(encrypted_data) + cipher.final
puts plain #=> "Whackabad"

get random password with puppet function

I have a function that allow me to generate random password. My function is working well without a puppetmaster. When I tried with a master an error appear when I called the function :
Error 400 on SERVER: bad value for range
Here is my function:
module Puppet::Parser::Functions
newfunction(:get_random_password, :type => :rvalue, :doc => <<-EOS
Returns a random password.
EOS
) do |args|
raise(Puppet::ParseError, "get_random_password(): Wrong number of arguments " +
"given (#{args.size} for 1)") if args.size != 1
specials = ((33..33).to_a + (35..38).to_a + (40..47).to_a + (58..64).to_a + (91..93).to_a + (95..96).to_a + (123..125).to_a).pack('U*').chars.to_a
numbers = (0..9).to_a
alphal = ('a'..'z').to_a
alphau = ('A'..'Z').to_a
length = args[0]
CHARS = (alphal + specials + numbers + alphau)
pwd = CHARS.sort_by { rand }.join[0...length]
return pwd
end
end
The function is called in both case with $pwd = get_random_password(10).
When I specified the length directly in the function to 10 for example. The password is well generated in master mode.
Have you any idea why I can't specify the length value?
It's unclear why this works for puppet apply (if that's what you're insinuating), but the error is most likely a typing issue.
Try
length = args[0].to_i
To my Knowledge,For situations like this I use the puppet generate() function to create the random password and store it in a persistent data store on the master.
For instance,an SQLITE database or something. This way, the password is generated randomly if it does not exist and the same password is used if it does already exist.
It's important to have the resource always be managed, that way if the password is changed on the managed node Puppet will realize this, change it to the value you're managing, and report that it did so.

Resources