1
0
Fork 0
mirror of https://github.com/eosswedenorg/antelope-keygen synced 2026-06-17 03:50:03 +02:00

Merge branch 'dictionary' into develop

# Conflicts:
#	CMakeLists.txt
#	src/main.cpp
This commit is contained in:
Henrik Hautakoski 2020-02-18 15:08:48 +01:00
commit f84f474290
19 changed files with 97183 additions and 19 deletions

View file

@ -6,6 +6,7 @@ project(eosio-keygen VERSION 0.1.6)
# Options
option(USE_THREADS "Compile with support for threads (if available)." ON)
option(FORCE_ANSI "Force ANSI console colors even on windows" OFF)
option(EXTRAS "Include non essential (extra) files in the build. (only for *nix)" OFF)
# Use installpath from GNUInstallDirs as default.
include(GNUInstallDirs)
@ -18,6 +19,7 @@ set (PROGRAM_EXE ${CMAKE_PROJECT_NAME})
set (PROGRAM_SOURCE
src/console.cpp
src/core/dictionary.cpp
src/string.cpp
src/base58.cpp
src/WIF.cpp
@ -41,6 +43,8 @@ set( CMAKE_CXX_EXTENSIONS OFF )
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wconversion -Wno-sign-conversion -Wextra" )
elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
add_definitions( "-D_CRT_SECURE_NO_WARNINGS=1" )
endif()
# Libraries
@ -59,6 +63,10 @@ if (USE_THREADS)
endif (Threads_FOUND)
endif (USE_THREADS)
# Project config file
configure_file(src/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY)
include_directories(${PROJECT_BINARY_DIR})
# Include OpenSSL headers
include_directories( ${OPENSSL_INCLUDE_DIR} )
@ -120,3 +128,11 @@ if (UNIX) # Only include in bash environments.
FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
)
endif (UNIX)
# --------------------------------
# Extras
# --------------------------------
if (UNIX AND EXTRAS)
add_subdirectory(extras)
endif()

View file

@ -17,6 +17,8 @@ search
.OP -m
.OP \--l33t
.OP \--threads=<num>
.OP \--dict=<file1> ...
.OP \--lang=<value> ...
.B word_list
.OP count
.YS
@ -60,6 +62,25 @@ Use
.I <num>
of parallel threads for searching. Default is what the operating system recomends.
.TP 20
.B --dict=<file>
Use words found in
.I <file>
(separated by newline) to highlight words in the keys found (note that the words in this
file are not used for search. only for highlight output). There can be more then one
.B --dict
flag. In that case contents of all files are merged into one dictionary.
.TP 20
.B --lang=<value>
Same as
.B --dict
but will use
.I <value>
to find a file in
.B @CMAKE_INSTALL_FULL_DATADIR@/@CMAKE_PROJECT_NAME@/dict.
There can be more then one
.B --lang
flag. In that case contents of all files are merged into one dictionary.
.TP 20
.B count
Number of keys to search for (default is 10)
.RE 1

49
extras/CMakeLists.txt Normal file
View file

@ -0,0 +1,49 @@
cmake_minimum_required(VERSION 3.4)
# Project name and version
project(eosio-keygen-extras VERSION 0.1.0)
# --------------------------------
# Package info
# --------------------------------
set( PACKAGE_NAME ${PROJECT_NAME} )
set( PACKAGE_DESCRIPTION "Extra files for eosio-keygen" )
set( PACKAGE_VERSION "${PROJECT_VERSION}" )
set( PACKAGE_URL "https://github.com/eosswedenorg/eosio-keygen" )
set( PACKAGE_MAINTAINER "Henrik Hautakoski <henrik@eossweden.org>")
# Debian specific
set( PACKAGE_DEB_RELEASE 1 CACHE STRING "Debian package release number")
set( PACKAGE_DEB_VERSION ${PACKAGE_VERSION}-${PACKAGE_DEB_RELEASE} )
set( PACKAGE_DEB_FILENAME ${PACKAGE_NAME}_${PACKAGE_DEB_VERSION}.deb )
# --------------------------------
# Debian package
# --------------------------------
set( DEB_ROOT "debroot" )
set( DEB_FULL_ROOT ${CMAKE_CURRENT_BINARY_DIR}/${DEB_ROOT} )
set( DEB_SHARE_DIR ${CMAKE_INSTALL_FULL_DATADIR}/${CMAKE_PROJECT_NAME} )
configure_file(debian_control.in ${DEB_ROOT}/DEBIAN/control @ONLY)
add_custom_target(deb_content
COMMAND ${CMAKE_COMMAND} -E copy_directory
dict
${DEB_FULL_ROOT}/${DEB_SHARE_DIR}/dict
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(deb_extras
COMMENT "dpkg: ${PROJECT_NAME} (${PACKAGE_DEB_FILENAME})"
COMMAND fakeroot dpkg-deb --build ${DEB_ROOT} ${PACKAGE_DEB_FILENAME} > /dev/null
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS deb_content
)
# --------------------------------
# Install target
# --------------------------------
install(
DIRECTORY dict
DESTINATION ${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}
)

8
extras/debian_control.in Normal file
View file

@ -0,0 +1,8 @@
Package: @PACKAGE_NAME@
Version: @PACKAGE_DEB_VERSION@
Description: @PACKAGE_DESCRIPTION@
Section: misc
Priority: optional
Architecture: all
Homepage: @PACKAGE_URL@
Maintainer: @PACKAGE_MAINTAINER@

8
extras/dict.json Normal file
View file

@ -0,0 +1,8 @@
{
"english": [
"/usr/share/dict/american-english",
"/usr/share/dict/british-english",
"english-custom"
],
"swedish": "/usr/share/dict/swedish"
}

47032
extras/dict/english Normal file

File diff suppressed because it is too large Load diff

49697
extras/dict/swedish Normal file

File diff suppressed because it is too large Load diff

8
extras/english-custom Normal file
View file

@ -0,0 +1,8 @@
bitcoin
bos
btc
dac
eos
eosio
swe
wax

15
scripts/generate-dict.sh Executable file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Generates a dictionary file for usage with eosio-keygen
# - input is read from stdin and should have words separated by newline.
# - output is written to stdout.
BASE58_ALPHABET=123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
# 1. Remove lines that are 2 or less characters long
# 2. Convert to lowercase
# 3. Remove any line that contains non base58 characters
# 4. Sort and remove duplicate lines.
LC_CTYPE=C sed -r '/^.{,2}$/d' < /dev/stdin 2> /dev/null \
| tr '[:upper:]' '[:lower:]' \
| awk "! /[^${BASE58_ALPHABET}]/" \
| sort | uniq

25
scripts/update-dict.sh Executable file
View file

@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Updates the dictionary files defined in extras/dict.json.
BASE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
EXTRAS_DIR=${BASE_DIR}/../extras
CONFIG=${EXTRAS_DIR}/dict.json
for lang in $(jq -r 'keys[]' $CONFIG); do
echo "- Generating: $lang"
files=()
for f in $(jq -r ".$lang | if type==\"array\" then .[] else . end" $CONFIG); do
if [ "${f:0:1}" != "/" ]; then
f="$EXTRAS_DIR/$f"
fi
files+=( "$f" )
done
grep -hs ^ ${files[@]} | $BASE_DIR/generate-dict.sh > $EXTRAS_DIR/dict/$lang
done
echo "Done"

31
src/config.h.in Normal file
View file

@ -0,0 +1,31 @@
/**
* MIT License
*
* Copyright (c) 2019-2020 EOS Sw/eden
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef CONFIG_H
#define CONFIG_H
// Paths
#define CONFIG_SHARE_PATH "@CMAKE_INSTALL_DATADIR@/@CMAKE_PROJECT_NAME@"
#define CONFIG_SHARE_FULL_PATH "@CMAKE_INSTALL_FULL_DATADIR@/@CMAKE_PROJECT_NAME@"
#endif /* CONFIG_H */

106
src/core/dictionary.cpp Normal file
View file

@ -0,0 +1,106 @@
#include <iostream>
#include <cstdio>
#include <iterator>
#include <algorithm>
#include "../string.h"
#include "dictionary.h"
namespace eoskeygen {
struct StringContains {
StringContains(const std::string& str, std::vector<size_t>& pos) : m_str(str), m_pos(pos) {}
bool operator()(const std::string& w) {
for(size_t p = m_str.find(w); p != std::string::npos; p = m_str.find(w, p+1)) {
m_pos.push_back(p);
}
return !m_pos.empty();
}
std::string m_str;
std::vector<size_t>& m_pos;
};
bool Dictionary::loadFromFile(const std::string& filename)
{
FILE *fd;
char buf[1024];
fd = fopen(filename.c_str(), "r");
if (!fd) {
return false;
}
// Clear before adding.
clear();
// Read each line and add to the dictionary.
while(fgets(buf, sizeof(buf), fd) != NULL) {
std::string word(buf);
add(trim(word));
}
fclose(fd);
return true;
}
void Dictionary::add(const std::string& word)
{
// Do not insert a empty string.
if (word.length()) {
m_words.insert(word);
}
}
void Dictionary::add(const Dictionary& dictionary)
{
std::set_union(
m_words.begin(), m_words.end(),
dictionary.m_words.begin(), dictionary.m_words.end(),
std::inserter(m_words, m_words.begin())
);
}
void Dictionary::clear()
{
m_words.clear();
}
bool Dictionary::contains(const std::string& word) const
{
return m_words.find(word) != m_words.cend();
}
Dictionary::search_result_t Dictionary::search(const std::string& subject) const
{
search_result_t res;
std::vector<size_t> pos;
StringContains pred(subject, pos);
// Find all words.
for(auto it = std::find_if(m_words.begin(), m_words.end(), pred);
it != m_words.end();
it = std::find_if(++it, m_words.end(), pred)) {
// Go through all found positions.
for (auto it2 = pos.begin(); it2 != pos.end(); it2++) {
// Insert
auto rit = res.find(*it2);
if (rit == res.end()) {
res.emplace(*it2, it->length());
}
// Update length if it's longer then the previous we found.
else if (rit->second < it->length()) {
rit->second = it->length();
}
}
// Clear positions
pos.clear();
}
return res;
}
} // namespace eoskeygen

72
src/core/dictionary.h Normal file
View file

@ -0,0 +1,72 @@
/**
* MIT License
*
* Copyright (c) 2019-2020 EOS Sw/eden
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef EOSIOKEYGEN_DICTIONARY_H
#define EOSIOKEYGEN_DICTIONARY_H
#include <vector>
#include <string>
#include <map>
#include <set>
namespace eoskeygen {
class Dictionary
{
public :
//typedef std::map< std::string, std::vector<size_t> > search_result_t;
// index = position in the search string.
// value = length of the word from this position.
typedef std::map< size_t, size_t > search_result_t;
public :
// Load words from file.
bool loadFromFile(const std::string& filename);
// Add a word
void add(const std::string& word);
// Add words from another dictionary.
void add(const Dictionary& dictionary);
void clear();
// Returns true if word exists in the dictionary.
bool contains(const std::string& word) const;
// Searches the subject for words defined in the dictionary.
// Returns a map with the word as key and a vector<int>
// of each position the word was found.
search_result_t search(const std::string& subject) const;
protected :
// Words in the dictionary.
std::set<std::string> m_words;
};
} // namespace eoskeygen
#endif /* EOSIOKEYGEN_DICTIONARY_H */

View file

@ -43,6 +43,11 @@ void KeySearch::addList(const strlist_t& list)
}
}
void KeySearch::addDictionary(const Dictionary& dictionary)
{
m_dict = dictionary;
}
const strlist_t& KeySearch::getList()
{
return m_words;
@ -62,7 +67,7 @@ void KeySearch::_search_linear(size_t n) {
struct key_result res;
ec_generate_key(&pair);
if (key_contains_word(&pair, m_words, &res)) {
key_search_result(&pair, &res);
key_search_result(&pair, &res, m_dict);
count++;
}
}

View file

@ -24,6 +24,7 @@
#ifndef EOSIOKEYGEN_KEY_SEARCH_H
#define EOSIOKEYGEN_KEY_SEARCH_H
#include "core/dictionary.h"
#include "string.h"
namespace eoskeygen {
@ -37,6 +38,8 @@ public :
// Add a list of words to search for.
void addList(const strlist_t& list);
void addDictionary(const Dictionary& dictionary);
// get the list of words to search for.
const strlist_t& getList();
@ -54,6 +57,8 @@ public :
protected :
#ifdef HAVE_THREADS
void _thr_proc();
void _search_mt(size_t n);
#endif /* HAVE_THREADS */
@ -63,6 +68,9 @@ protected :
// List of words to search for.
strlist_t m_words;
// Dictionary to use when we find a search result.
Dictionary m_dict;
#ifdef HAVE_THREADS
// Number of threads to use.
size_t m_threads;

View file

@ -22,27 +22,48 @@
* SOFTWARE.
*/
#include <iostream>
#include "core/dictionary.h"
#include "WIF.h"
#include "console.h"
#include "key_search_helpers.h"
namespace eoskeygen {
void key_search_result(const struct ec_keypair* key, const struct key_result* result) {
static size_t highlight(console::Color color, const std::string& str, size_t pos, size_t len) {
std::cout << console::fg(color, console::bold)
<< str.substr(pos, len)
<< console::reset;
return len;
}
void key_search_result(const struct ec_keypair* key, const struct key_result* result, const Dictionary& dict) {
std::string pub = wif_pub_encode(key->pub);
std::string word = pub.substr(result->pos, result->len);
Dictionary::search_result_t dict_res = dict.search(pub);
std::cout << "----" << std::endl;
std::cout << "Found: " << word << std::endl;
std::cout << "Found: " << pub.substr(result->pos, result->len) << std::endl;
std::cout << "Public: "
<< pub.substr(0, result->pos)
<< console::fg(console::red, console::bold) << word << console::reset
<< pub.substr(result->pos + result->len)
<< std::endl;
std::cout << "Public: EOS";
for(size_t i = 3; i < pub.length(); ) {
std::cout << "Private: " << wif_priv_encode(key->secret) << std::endl;
if (i == result->pos) {
i += highlight(console::red, pub, result->pos, result->len);
continue;
}
auto p = dict_res.find(i);
if (p != dict_res.end()) {
i += highlight(console::blue, pub, p->first, p->second);
continue;
}
std::cout << pub[i++];
}
std::cout << std::endl
<< "Private: " << wif_priv_encode(key->secret) << std::endl;
}
bool key_contains_word(const struct ec_keypair* key, const strlist_t& word_list, struct key_result *result) {

View file

@ -29,12 +29,14 @@
namespace eoskeygen {
class Dictionary;
struct key_result {
size_t pos; // position where the word was found.
size_t len; // the length of the word.
};
void key_search_result(const struct ec_keypair* key, const struct key_result* result);
void key_search_result(const struct ec_keypair* key, const struct key_result* result, const Dictionary& dict);
// Check if any word in <word_list> appears in <key>'s public key.
// returns true if a word was found (stored in <result>), false otherwise.

View file

@ -41,7 +41,7 @@ std::size_t g_count;
std::mutex g_count_mtx;
// Thread process.
static void _thr_proc(const strlist_t& word_list) {
void KeySearch::_thr_proc() {
struct ec_keypair pair;
@ -49,7 +49,7 @@ static void _thr_proc(const strlist_t& word_list) {
struct key_result res;
ec_generate_key(&pair);
if (key_contains_word(&pair, word_list, &res)) {
if (key_contains_word(&pair, m_words, &res)) {
// Guard output with mutex, so we don't get
// interrupted mid write and can write to g_count safely.
@ -64,7 +64,7 @@ static void _thr_proc(const strlist_t& word_list) {
// Update count and print result.
g_count++;
key_search_result(&pair, &res);
key_search_result(&pair, &res, m_dict);
}
}
}
@ -86,11 +86,11 @@ void KeySearch::_search_mt(size_t n)
// Launch them.
for(std::size_t i = 0; i < t.size(); i++) {
t[i] = std::thread(_thr_proc, m_words);
t[i] = std::thread(&KeySearch::_thr_proc, this);
}
// Use main thread for 1 search
_thr_proc(m_words);
_thr_proc();
// Wait for all threads to compelete.
for(std::size_t i = 0; i < t.size(); i++) {

View file

@ -27,6 +27,8 @@
#include <iostream>
#include <cstring>
#include "console.h"
#include "config.h"
#include "core/dictionary.h"
#include "string.h"
#include "WIF.h"
#include "crypto/ec.h"
@ -40,10 +42,12 @@ bool option_l33t = false;
int option_num_threads = std::thread::hardware_concurrency();
#endif /* HAVE_THREADS */
void cmd_search(const eoskeygen::strlist_t& words, int count) {
void cmd_search(const eoskeygen::strlist_t& words, const eoskeygen::Dictionary& dict, int count) {
eoskeygen::KeySearch ks;
ks.addDictionary(dict);
if (option_l33t) {
for(std::size_t i = 0; i < words.size(); i++) {
ks.addList(eoskeygen::l33twords(words[i]));
@ -73,7 +77,8 @@ void usage(const char *name) {
#ifdef HAVE_THREADS
<< " | --threads=<num>"
#endif /* HAVE_THREADS */
<< " ] <word_list> [ <count:10> ]"
<< " | --dict=<file> ... "
<< " | --lang=<value> ... ] <word_list> [ <count:10> ]"
<< " | benchmark [ <num:1000> ]"
<< " ]"
<< std::endl << std::endl;
@ -100,6 +105,17 @@ void usage(const char *name) {
<< " --threads=<num>: Use <num> of parallel threads for searching." << std::endl
<< " Default is what the operating system recomend."
#endif /* HAVE_THREADS */
<< std::endl << std::endl
<< " --dict=<file>: Use words found in <file> (separated by newline) to" << std::endl
<< " highlight words in the keys found (note that the words in this" << std::endl
<< " file are not used for search. only for highlight output)." << std::endl
<< " There can be more then one --dict flag. In that case contents" << std::endl
<< " of all files are merged into one dictionary." << std::endl
<< std::endl << std::endl
<< " --lang=<value>: Same as --dict but will use <value>" << std::endl
<< " to find a file in " << CONFIG_SHARE_FULL_PATH << "/dict." << std::endl
<< " There can be more then one --lang flag. In that case contents" << std::endl
<< " of all files are merged into one dictionary." << std::endl
<< std::endl;
std::cout << " Benchmark: " << std::endl
@ -143,6 +159,7 @@ int main(int argc, char **argv) {
int count = 10;
eoskeygen::strlist_t words;
eoskeygen::Dictionary dict;
while(p++ < argc - 1) {
if (!strcmp(argv[p], "-m")) {
@ -164,6 +181,29 @@ int main(int argc, char **argv) {
<< " thread support. this option is ignored." << std::endl;
#endif /* HAVE_THREADS */
}
// Dictionary.
else if (!memcmp(argv[p], "--dict=", 7)) {
eoskeygen::Dictionary d;
std::string filename(argv[p] + 7);
if (d.loadFromFile(filename)) {
dict.add(d);
} else {
std::cerr << "Could not load dictionary from file: " << filename << std::endl;
}
}
// Language (dictionary, but we find the file in <CONFIG_SHARE_FULL_PATH>/dict/<lang>)
else if (!memcmp(argv[p], "--lang=", 7)) {
eoskeygen::Dictionary d;
std::string lang(argv[p] + 7);
std::string filename(std::string(CONFIG_SHARE_FULL_PATH) + "/dict" + lang);
if (d.loadFromFile(filename)) {
dict.add(d);
} else {
std::cerr << "Could not load language " << lang << " (" << filename << ")" << std::endl;
}
}
// Error out on any flag we don't support.
else if (argv[p][0] == '-') {
std::cerr << "Unrecognized flag: " << argv[p] << std::endl;
@ -189,7 +229,7 @@ int main(int argc, char **argv) {
return 1;
}
cmd_search(words, count);
cmd_search(words, dict, count);
}
// Benchmark
else if (!strcmp(argv[p], "benchmark")) {