lib/net: Implement a way to generate fingerprint randomart
The code has been copied from OpenSSH.
This commit is contained in:
parent
a238b27879
commit
b7757fbd68
|
@ -13,9 +13,36 @@
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
create_fingerprint_randomart() has been taken from the OpenSSH project.
|
||||||
|
Copyright information follows.
|
||||||
|
|
||||||
|
Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||||
|
Copyright (c) 2008 Alexander von Gernler. All rights reserved.
|
||||||
|
Copyright (c) 2010,2011 Damien Miller. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "FingerprintDatabase.h"
|
|
||||||
#include "SecureUtils.h"
|
#include "SecureUtils.h"
|
||||||
#include "base/String.h"
|
#include "base/String.h"
|
||||||
#include "base/finally.h"
|
#include "base/finally.h"
|
||||||
|
@ -25,7 +52,9 @@
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
|
#include <algorithm>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace barrier {
|
namespace barrier {
|
||||||
|
@ -142,4 +171,113 @@ void generate_pem_self_signed_cert(const std::string& path)
|
||||||
PEM_write_X509(fp, cert);
|
PEM_write_X509(fp, cert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Draw an ASCII-Art representing the fingerprint so human brain can
|
||||||
|
profit from its built-in pattern recognition ability.
|
||||||
|
This technique is called "random art" and can be found in some
|
||||||
|
scientific publications like this original paper:
|
||||||
|
|
||||||
|
"Hash Visualization: a New Technique to improve Real-World Security",
|
||||||
|
Perrig A. and Song D., 1999, International Workshop on Cryptographic
|
||||||
|
Techniques and E-Commerce (CrypTEC '99)
|
||||||
|
sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
|
||||||
|
|
||||||
|
The subject came up in a talk by Dan Kaminsky, too.
|
||||||
|
|
||||||
|
If you see the picture is different, the key is different.
|
||||||
|
If the picture looks the same, you still know nothing.
|
||||||
|
|
||||||
|
The algorithm used here is a worm crawling over a discrete plane,
|
||||||
|
leaving a trace (augmenting the field) everywhere it goes.
|
||||||
|
Movement is taken from dgst_raw 2bit-wise. Bumping into walls
|
||||||
|
makes the respective movement vector be ignored for this turn.
|
||||||
|
Graphs are not unambiguous, because circles in graphs can be
|
||||||
|
walked in either direction.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Field sizes for the random art. Have to be odd, so the starting point
|
||||||
|
can be in the exact middle of the picture, and FLDBASE should be >=8 .
|
||||||
|
Else pictures would be too dense, and drawing the frame would
|
||||||
|
fail, too, because the key type would not fit in anymore.
|
||||||
|
*/
|
||||||
|
#define FLDBASE 8
|
||||||
|
#define FLDSIZE_Y (FLDBASE + 1)
|
||||||
|
#define FLDSIZE_X (FLDBASE * 2 + 1)
|
||||||
|
|
||||||
|
std::string create_fingerprint_randomart(const std::vector<std::uint8_t>& dgst_raw)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Chars to be used after each other every time the worm
|
||||||
|
* intersects with itself. Matter of taste.
|
||||||
|
*/
|
||||||
|
const char* augmentation_string = " .o+=*BOX@%&#/^SE";
|
||||||
|
char *p;
|
||||||
|
std::uint8_t field[FLDSIZE_X][FLDSIZE_Y];
|
||||||
|
std::size_t i;
|
||||||
|
std::uint32_t b;
|
||||||
|
int x, y;
|
||||||
|
std::size_t len = strlen(augmentation_string) - 1;
|
||||||
|
|
||||||
|
std::vector<char> retval;
|
||||||
|
retval.reserve((FLDSIZE_X + 3) * (FLDSIZE_Y + 2));
|
||||||
|
|
||||||
|
auto add_char = [&retval](char ch) { retval.push_back(ch); };
|
||||||
|
|
||||||
|
/* initialize field */
|
||||||
|
std::memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
|
||||||
|
x = FLDSIZE_X / 2;
|
||||||
|
y = FLDSIZE_Y / 2;
|
||||||
|
|
||||||
|
/* process raw key */
|
||||||
|
for (i = 0; i < dgst_raw.size(); i++) {
|
||||||
|
/* each byte conveys four 2-bit move commands */
|
||||||
|
int input = dgst_raw[i];
|
||||||
|
for (b = 0; b < 4; b++) {
|
||||||
|
/* evaluate 2 bit, rest is shifted later */
|
||||||
|
x += (input & 0x1) ? 1 : -1;
|
||||||
|
y += (input & 0x2) ? 1 : -1;
|
||||||
|
|
||||||
|
/* assure we are still in bounds */
|
||||||
|
x = std::max(x, 0);
|
||||||
|
y = std::max(y, 0);
|
||||||
|
x = std::min(x, FLDSIZE_X - 1);
|
||||||
|
y = std::min(y, FLDSIZE_Y - 1);
|
||||||
|
|
||||||
|
/* augment the field */
|
||||||
|
if (field[x][y] < len - 2)
|
||||||
|
field[x][y]++;
|
||||||
|
input = input >> 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mark starting point and end point*/
|
||||||
|
field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
|
||||||
|
field[x][y] = len;
|
||||||
|
|
||||||
|
/* output upper border */
|
||||||
|
add_char('+');
|
||||||
|
for (i = 0; i < FLDSIZE_X; i++)
|
||||||
|
add_char('-');
|
||||||
|
add_char('+');
|
||||||
|
add_char('\n');
|
||||||
|
|
||||||
|
/* output content */
|
||||||
|
for (y = 0; y < FLDSIZE_Y; y++) {
|
||||||
|
add_char('|');
|
||||||
|
for (x = 0; x < FLDSIZE_X; x++)
|
||||||
|
add_char(augmentation_string[std::min<int>(field[x][y], len)]);
|
||||||
|
add_char('|');
|
||||||
|
add_char('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* output lower border */
|
||||||
|
add_char('+');
|
||||||
|
for (i = 0; i < FLDSIZE_X; i++)
|
||||||
|
add_char('-');
|
||||||
|
add_char('+');
|
||||||
|
|
||||||
|
return std::string{retval.data(), retval.size()};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace barrier
|
} // namespace barrier
|
||||||
|
|
|
@ -35,6 +35,8 @@ FingerprintData get_pem_file_cert_fingerprint(const std::string& path, Fingerpri
|
||||||
|
|
||||||
void generate_pem_self_signed_cert(const std::string& path);
|
void generate_pem_self_signed_cert(const std::string& path);
|
||||||
|
|
||||||
|
std::string create_fingerprint_randomart(const std::vector<std::uint8_t>& dgst_raw);
|
||||||
|
|
||||||
} // namespace barrier
|
} // namespace barrier
|
||||||
|
|
||||||
#endif // BARRIER_LIB_NET_SECUREUTILS_H
|
#endif // BARRIER_LIB_NET_SECUREUTILS_H
|
||||||
|
|
|
@ -30,4 +30,44 @@ TEST(SecureUtilsTest, FormatSslFingerprintHexWithSeparators)
|
||||||
"CA:B2:8E:49:25:94:90:25:26:05:8D:AF:63:ED:2E:30");
|
"CA:B2:8E:49:25:94:90:25:26:05:8D:AF:63:ED:2E:30");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SecureUtilsTest, CreateFingerprintRandomArt)
|
||||||
|
{
|
||||||
|
ASSERT_EQ(create_fingerprint_randomart(generate_pseudo_random_bytes(0, 32)),
|
||||||
|
"+-----------------+\n"
|
||||||
|
"|*X+. . |\n"
|
||||||
|
"|*oo + |\n"
|
||||||
|
"| + = |\n"
|
||||||
|
"| B . . |\n"
|
||||||
|
"|.+... o S |\n"
|
||||||
|
"|E+ ++. . |\n"
|
||||||
|
"|B*++.. . |\n"
|
||||||
|
"|+o*o o . |\n"
|
||||||
|
"|+o*Bo . |\n"
|
||||||
|
"+-----------------+");
|
||||||
|
ASSERT_EQ(create_fingerprint_randomart(generate_pseudo_random_bytes(1, 32)),
|
||||||
|
"+-----------------+\n"
|
||||||
|
"| .oo+ . .B=. |\n"
|
||||||
|
"| .o.+ . o o.= |\n"
|
||||||
|
"|o..+.. o . E * |\n"
|
||||||
|
"|oo..+ . * * |\n"
|
||||||
|
"|B o.....S. o . |\n"
|
||||||
|
"|+=o..... |\n"
|
||||||
|
"| + + . |\n"
|
||||||
|
"|o. .. |\n"
|
||||||
|
"|..o.. |\n"
|
||||||
|
"+-----------------+");
|
||||||
|
ASSERT_EQ(create_fingerprint_randomart(generate_pseudo_random_bytes(2, 32)),
|
||||||
|
"+-----------------+\n"
|
||||||
|
"| ... .o.o.|\n"
|
||||||
|
"| o .=.E|\n"
|
||||||
|
"| . + o ...+.|\n"
|
||||||
|
"| * o = o ... |\n"
|
||||||
|
"| * + S & . |\n"
|
||||||
|
"| = + % @ |\n"
|
||||||
|
"| . . = X o |\n"
|
||||||
|
"| . . O . |\n"
|
||||||
|
"| . + |\n"
|
||||||
|
"+-----------------+");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace barrier
|
} // namespace barrier
|
||||||
|
|
Loading…
Reference in New Issue