Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
byt3n33dl3 authored May 29, 2024
1 parent 597c25e commit 86aa1d3
Show file tree
Hide file tree
Showing 7 changed files with 515 additions and 0 deletions.
129 changes: 129 additions & 0 deletions Parser/imp/doh/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# DOmain Hash password generator (DOH)

The Domain Hash Password Generator (DOH) uses hashes to generate unique passwords for each domain from a single master password.

## Features

* Passwords are cryptographically secure.
* Passwords are never stored anywhere. Not even on your own computer.
* Passwords are guaranteed to be accepted by the website.\*
* Passwords are reproducible from a single master password.
* Multiple hashing strategies are available.

\* Given a correct domain specification (see below).

## Visuals

After installation, the patented "DOH it!" button appears in password fields.

![Username](https://raw.githubusercontent.com/amozoss/doh/master/images/username.png)

Pressing "DOH it!" instantly generates your secure password.

![Password](https://raw.githubusercontent.com/amozoss/doh/master/images/password_generated.png)

## Description

DOH generates passwords based on a domain, master password, and salt. Each site has different passwords, and DOH can generate passwords that are guaranteed to have the right number of special characters, uppercase letters, numbers, etc. The algorithm does not save any state, so any computer you use can generate your passwords with information from your head -- without any syncing. This also means there is no database to be hacked or service provider you need to trust.

DOH is entirely opensource, so you can audit the code yourself to make sure your passwords are safe.

The following have been implemented:

* Pure javascript HTML webpage generator
* Chromium plugin
* Firefox plugin (unfinished; see branches)



##Installation

You need some flavor of ruby installed (it converts the yaml file to json).

git clone https:/onionjake/doh.git
cd doh
./setup

### Chromium Plugin

<launch chrome/chromium>
Type in 'chrome://extensions' in the address bar
Check 'Developer mode'
Load unpacked extension
Browse to 'doh/chromium' and click Open

### HTML (any browser)

<launch browser>
Type 'file://<cloned location>/doh/html/index.html' into the address bar
<or>
Goto 'https://onionjake.github.io/doh/'


## Terminology

Master Password: Your secret password. This should be long, secure, and follow all good password conventions.

Salt: This is something unique to you. It does not need to be secret or hard to guess, just memorable. Something like your email address or your favorite online username is good.

Domain: This is part of the URL of the website. It does not include www or anything else ahead of the domain.

Examples:

https://github.com/onionjake/doh - github.com

https://login.yahoo.com - yahoo.com

## Use

### Chromium Plugin

TODO

### HTML (any browser)

Read terminology section above
Enter Master Password
Enter Salt
Enter Domain
Enter Seqeunce String (optional)
Click 'Generate Password'
Copy and paste generated password into website.

## The algorithm

Here is the algorithm in a nutshell:

1. User enters salt (username, name, or something memorable but unique), master password, and domain, and an optional sequence number.
2. Compute PBKDF2(sha512, sha256(salt + master password), sequence + domain + salt, 2000, <varies on domain spec>) and output in base64.\* Remove padding characters ('=').
3. Based on a domain specification (shipped with program or provided by user), translate standard base64 to a new base64 with characters from the required character set for given domain.
4. Search result for password that meets all requirements set in the domain spec.
5. If password cannot be found, rotate a bit and search again.
6. If password cannot be found after 5 rotations, rehash and search again.

\* Where '+' is concatenation. See http://en.wikipedia.org/wiki/PBKDF2 on PBKDF2 function definition.

The expected number of characters needed to fulfill typical password requirements is 10 characters. Determining each domain's expected number of minimum characters to meet requirements can be done using the coupon collectors problem.

## Domain Specifications

TODO

## License

Copyright (c) 2016 Jake Willoughby

This file is part of DOH.

DOH is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.

DOH is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with DOH. See gpl3.txt. If not, see <http://www.gnu.org/licenses/>.
83 changes: 83 additions & 0 deletions Parser/imp/doh/alt64_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env ruby
# Copyright (c) 2016 Jake Willoughby
#
# This file is part of DOH.
#
# DOH is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# DOH is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with DOH. See gpl3.txt. If not, see <http://www.gnu.org/licenses/>.

require "pp"
require "optparse"
require "set"

OptionParser.new do |o|
o.on('--not [characters]') { |b| $not = b }
o.on('-h') { puts o; exit }
o.parse!
end

$a = {}
$a["lower"] = "abcdefghijklmnopqrstuvwxyz"
$a["upper"] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
$a["number"] = "0123456789"
$a["special"] = " !\"#\$%&'()*+,-./:;<=>?@[\\]^_`{|}~"

$a = $a.map do |k,v|
[k, v.chars.sort.join]
end.to_h
TOTAL = 64

$out = ""

puts "Give me one or more of '#{$a.keys.join ' '}' as arguments" if ARGV.length == 0

def red(s)
"\e[31m#{s}\e[0m"
end
def yellow(s)
"\e[33m#{s}\e[0m"
end

sets = ARGV.map {|b|
abort red("Error: #{b} is not one of '#{$a.keys.join ' '}'.") unless $a.has_key? b
$a[b]
}

sets.sort_by { |v|
v.length
}.each_with_index { |b, i|
b.delete! $not if $not
want = (TOTAL - $out.length) / (sets.length - i)
#puts "want #{want} = #{(TOTAL - $out.length)} / #{(sets.length - i)}"
want = b.length if b.length < want
$out += b.chars.sort.join[0..want-1]
}

if $out.length != 64
abort red("Error: Got '#{$out}' of length #{$out.length} which != 64")
end


u = Set.new $out.chars
# figure out which characters are duplicated
dups = $out.chars.reject { |c| u.delete(c) if u.include?(c) }
dl = dups.length
if dl > 0
abort red("Error: The character#{dl>1?'s':''} '#{dups.join}' occur#{dl>1?'':'s'} more than once. This reduces entropy and is not safe!")
end

$out = $out.chars.sort.join

puts yellow("#{' '*$out.index(' ')}/---- Note: don't forget to include the space") if $out =~ / /

puts $out
24 changes: 24 additions & 0 deletions Parser/imp/doh/convert.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env ruby
# Copyright (c) 2016 Jake Willoughby
#
# This file is part of DOH.
#
# DOH is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# DOH is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with DOH. See gpl3.txt. If not, see <http://www.gnu.org/licenses/>.
require "json"
require "yaml"
require "pp"

$specs = YAML.load(File.open("domain_specs.yaml"))

puts JSON.pretty_generate($specs)
139 changes: 139 additions & 0 deletions Parser/imp/doh/doh
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#!/usr/bin/env ruby
# Copyright (c) 2016 Jake Willoughby
#
# This file is part of DOH.
#
# DOH is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# DOH is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with DOH. See gpl3.txt. If not, see <http://www.gnu.org/licenses/>.

require 'openssl'
require "base64"
require "open3"
require 'io/console'
require "yaml"
require 'date'

require_relative "./doh"

file = __FILE__
file = File.readlink(file) if File.symlink? file

SCRIPT_DIR = File.dirname(file)

def red(s)
"\e[31m#{s}\e[0m"
end
def yellow(s)
"\e[33m#{s}\e[0m"
end
def green(s)
"\e[32m#{s}\e[0m"
end

salt = ARGV.shift
unless salt
puts "Usage: #{$0} <salt>"
abort red("Error: no salt given")
end

$specs = YAML.load(File.open(SCRIPT_DIR + "/domain_specs.yaml"))

print "Password: "
pass = $stdin.noecho(&:gets).strip
puts

iterations = 10000

digest = OpenSSL::Digest::SHA256.new
ss = Digest::SHA256.digest(salt + pass)
id = Digest::SHA256.hexdigest(salt + pass)[-4..-1]
puts "Your master password id is #{red(id)}"

print "Pin: "
pin = $stdin.noecho(&:gets).strip
puts
puts

$pin_attempts = 0

xclip = File.exist?("/usr/bin/xclip")
pbcopy = File.exist?("/usr/bin/pbcopy")


while true
print "Domain: "
domain = $stdin.gets.strip
unless domain
puts red("Error: no domain given")
end

if $specs.has_key? domain
myspec = $specs[domain]
puts "got domain"
else
myspec = $specs["defaults"]
end
print "Sequence: "
seq = $stdin.gets.strip
seq = "" unless seq

print "Pin: "
check_pin = $stdin.noecho(&:gets).strip
puts

if pin.strip != check_pin.strip
$pin_attempts += 1
if $pin_attempts >= 3
abort red("Too many pin attempts!")
end
puts yellow("Incorrect pin!")
puts
next
end
$pin_attempts = 0

puts myspec['length']
pwd = doh(myspec, ss, seq, domain, salt, iterations, myspec['length'], digest)

File.open(ENV["HOME"] + "/.dohlog",'a') do |f|
f.puts "#{DateTime.now} #{domain} #{seq}"
end


if xclip || pbcopy
if xclip
Open3.popen2("xclip -i -selection clipboard") do |i,o,t|
i.print pwd
i.flush
i.close
t.value
end
end
if pbcopy
Open3.popen2("pbcopy") do |i,o,t|
i.print pwd
i.flush
i.close
t.value
end
end
puts "Password Copied to clipboard."
else
puts yellow("Generated Password:")
puts yellow("#{' '*pwd.index(' ')}/---- Note: don't forget to include the space") if pwd =~ / /
puts pwd
end

puts
end

Loading

0 comments on commit 86aa1d3

Please sign in to comment.