keepassxc/src/sshagent/OpenSSHKey.cpp

754 lines
22 KiB
C++
Raw Normal View History

2017-10-29 15:17:24 +00:00
/*
* Copyright (C) 2017 Toni Spets <toni.spets@iki.fi>
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
*
* This program 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 2 or (at your option)
* version 3 of the License.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "OpenSSHKey.h"
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
#include "ASN1Key.h"
#include "BinaryStream.h"
#include "core/Global.h"
#include "crypto/Random.h"
2018-03-31 20:01:30 +00:00
#include "crypto/SymmetricCipher.h"
2017-10-29 15:17:24 +00:00
#include <QRegularExpression>
#include <QStringList>
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
#include <botan/pwdhash.h>
const QString OpenSSHKey::TYPE_DSA_PRIVATE = "DSA PRIVATE KEY";
const QString OpenSSHKey::TYPE_RSA_PRIVATE = "RSA PRIVATE KEY";
const QString OpenSSHKey::TYPE_OPENSSH_PRIVATE = "OPENSSH PRIVATE KEY";
const QString OpenSSHKey::OPENSSH_CIPHER_SUFFIX = "@openssh.com";
2018-03-31 20:01:30 +00:00
OpenSSHKey::OpenSSHKey(QObject* parent)
: QObject(parent)
, m_check(0)
, m_type(QString())
, m_cipherName(QString("none"))
, m_kdfName(QString("none"))
, m_kdfOptions(QByteArray())
, m_rawType(QString())
, m_rawData(QByteArray())
, m_rawPublicData(QByteArray())
, m_rawPrivateData(QByteArray())
, m_comment(QString())
, m_error(QString())
, m_certificateType(QString())
, m_rawCertificateData(QByteArray())
2017-10-29 15:17:24 +00:00
{
}
OpenSSHKey::OpenSSHKey(const OpenSSHKey& other)
: QObject(nullptr)
, m_check(other.m_check)
, m_type(other.m_type)
, m_cipherName(other.m_cipherName)
, m_kdfName(other.m_kdfName)
, m_kdfOptions(other.m_kdfOptions)
, m_rawType(other.m_rawType)
, m_rawData(other.m_rawData)
, m_rawPublicData(other.m_rawPublicData)
, m_rawPrivateData(other.m_rawPrivateData)
, m_comment(other.m_comment)
, m_error(other.m_error)
, m_certificateType(other.m_certificateType)
, m_rawCertificateData(other.m_rawCertificateData)
2017-10-29 15:17:24 +00:00
{
}
bool OpenSSHKey::operator==(const OpenSSHKey& other) const
{
// close enough for now
return (fingerprint() == other.fingerprint());
}
const QString OpenSSHKey::cipherName() const
{
return m_cipherName;
}
const QString OpenSSHKey::type() const
{
return m_type;
}
const QString OpenSSHKey::certificateType() const
{
return m_certificateType;
}
const QString OpenSSHKey::fingerprint(QCryptographicHash::Algorithm algo) const
2017-10-29 15:17:24 +00:00
{
if (m_rawPublicData.isEmpty()) {
return tr("(encrypted)");
}
2017-10-29 15:17:24 +00:00
QByteArray publicKey;
BinaryStream stream(&publicKey);
stream.writeString(m_type);
stream.write(m_rawPublicData);
2017-10-29 15:17:24 +00:00
QByteArray rawHash = QCryptographicHash::hash(publicKey, algo);
if (algo == QCryptographicHash::Md5) {
QString md5Hash = QString::fromLatin1(rawHash.toHex());
QStringList md5HashParts;
for (int i = 0; i < md5Hash.length(); i += 2) {
md5HashParts.append(md5Hash.mid(i, 2));
}
return "MD5:" + md5HashParts.join(':');
} else if (algo == QCryptographicHash::Sha256) {
return "SHA256:" + QString::fromLatin1(rawHash.toBase64(QByteArray::OmitTrailingEquals));
}
2017-10-29 15:17:24 +00:00
return "HASH:" + QString::fromLatin1(rawHash.toHex());
2017-10-29 15:17:24 +00:00
}
const QString OpenSSHKey::comment() const
{
return m_comment;
}
const QString OpenSSHKey::publicKey() const
{
if (m_rawPublicData.isEmpty()) {
return {};
}
2017-10-29 15:17:24 +00:00
QByteArray publicKey;
BinaryStream stream(&publicKey);
stream.writeString(m_type);
stream.write(m_rawPublicData);
2017-10-29 15:17:24 +00:00
return m_type + " " + QString::fromLatin1(publicKey.toBase64()) + " " + m_comment;
}
const QString OpenSSHKey::privateKey()
{
QByteArray sshKey;
BinaryStream stream(&sshKey);
// magic
stream.write(QString("openssh-key-v1").toUtf8());
stream.write(static_cast<quint8>(0));
// cipher name
stream.writeString(QString("none"));
// kdf name
stream.writeString(QString("none"));
// kdf options
stream.writeString(QString(""));
// number of keys
stream.write(static_cast<quint32>(1));
// string wrapped public key
QByteArray publicKey;
BinaryStream publicStream(&publicKey);
writePublic(publicStream);
stream.writeString(publicKey);
// string wrapper private key
QByteArray privateKey;
BinaryStream privateStream(&privateKey);
// integrity check value
privateStream.write(m_check);
privateStream.write(m_check);
writePrivate(privateStream);
// padding for unencrypted key
for (quint8 i = 1; i <= privateKey.size() % 8; i++) {
privateStream.write(i);
}
stream.writeString(privateKey);
// encode to PEM format
QString out;
out += "-----BEGIN OPENSSH PRIVATE KEY-----\n";
auto base64Key = QString::fromUtf8(sshKey.toBase64());
for (int i = 0; i < base64Key.size(); i += 70) {
out += base64Key.midRef(i, 70);
out += "\n";
}
out += "-----END OPENSSH PRIVATE KEY-----\n";
return out;
}
2017-10-29 15:17:24 +00:00
const QString OpenSSHKey::errorString() const
{
return m_error;
}
void OpenSSHKey::setType(const QString& type)
{
m_type = type;
}
void OpenSSHKey::setCheck(quint32 check)
{
m_check = check;
}
void OpenSSHKey::setPublicData(const QByteArray& data)
2017-10-29 15:17:24 +00:00
{
m_rawPublicData = data;
2017-10-29 15:17:24 +00:00
}
void OpenSSHKey::setPrivateData(const QByteArray& data)
2017-10-29 15:17:24 +00:00
{
m_rawPrivateData = data;
2017-10-29 15:17:24 +00:00
}
void OpenSSHKey::setComment(const QString& comment)
{
m_comment = comment;
}
void OpenSSHKey::clearPrivate()
{
m_rawData.clear();
2017-10-29 15:17:24 +00:00
m_rawPrivateData.clear();
}
bool OpenSSHKey::extractPEM(const QByteArray& in, QByteArray& out)
2017-10-29 15:17:24 +00:00
{
QString pem = QString::fromLatin1(in);
QStringList rows = pem.split(QRegularExpression("(?:\r?\n|\r)"), Qt::SkipEmptyParts);
2017-10-29 15:17:24 +00:00
if (rows.length() < 3) {
m_error = tr("Invalid key file, expecting an OpenSSH key");
return false;
}
QString begin = rows.first();
QString end = rows.last();
QRegularExpressionMatch beginMatch = QRegularExpression("^-----BEGIN ([^\\-]+)-----$").match(begin);
QRegularExpressionMatch endMatch = QRegularExpression("^-----END ([^\\-]+)-----$").match(end);
if (!beginMatch.hasMatch() || !endMatch.hasMatch()) {
m_error = tr("Invalid key file, expecting an OpenSSH key");
return false;
}
if (beginMatch.captured(1) != endMatch.captured(1)) {
m_error = tr("PEM boundary mismatch");
return false;
}
m_rawType = beginMatch.captured(1);
2017-10-29 15:17:24 +00:00
rows.removeFirst();
rows.removeLast();
QRegularExpression keyValueExpr = QRegularExpression("^([A-Za-z0-9-]+): (.+)$");
QMap<QString, QString> pemOptions;
do {
QRegularExpressionMatch keyValueMatch = keyValueExpr.match(rows.first());
if (!keyValueMatch.hasMatch()) {
break;
}
pemOptions.insert(keyValueMatch.captured(1), keyValueMatch.captured(2));
rows.removeFirst();
} while (!rows.isEmpty());
if (pemOptions.value("Proc-Type").compare("4,encrypted", Qt::CaseInsensitive) == 0) {
m_kdfName = "md5";
m_cipherName = pemOptions.value("DEK-Info").section(",", 0, 0);
m_cipherIV = QByteArray::fromHex(pemOptions.value("DEK-Info").section(",", 1, 1).toLatin1());
}
2017-10-29 15:17:24 +00:00
out = QByteArray::fromBase64(rows.join("").toLatin1());
if (out.isEmpty()) {
m_error = tr("Base64 decoding failed");
return false;
}
return true;
}
bool OpenSSHKey::parsePKCS1PEM(const QByteArray& in)
2017-10-29 15:17:24 +00:00
{
QByteArray data;
if (!extractPEM(in, data)) {
2017-10-29 15:17:24 +00:00
return false;
}
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
if (m_rawType == TYPE_DSA_PRIVATE || m_rawType == TYPE_RSA_PRIVATE) {
m_rawData = data;
} else if (m_rawType == TYPE_OPENSSH_PRIVATE) {
BinaryStream stream(&data);
2017-10-29 15:17:24 +00:00
QByteArray magic;
magic.resize(15);
2017-10-29 15:17:24 +00:00
if (!stream.read(magic)) {
m_error = tr("Key file way too small.");
return false;
}
2017-10-29 15:17:24 +00:00
if (QString::fromLatin1(magic) != "openssh-key-v1") {
m_error = tr("Key file magic header id invalid");
return false;
}
2017-10-29 15:17:24 +00:00
if (!stream.readString(m_cipherName) || !stream.readString(m_kdfName) || !stream.readString(m_kdfOptions)) {
m_error = tr("Failed to read key file: %1").arg(stream.errorString());
return false;
}
2017-10-29 15:17:24 +00:00
quint32 numberOfKeys;
stream.read(numberOfKeys);
2017-10-29 15:17:24 +00:00
if (numberOfKeys == 0) {
m_error = tr("Found zero keys");
2017-10-29 15:17:24 +00:00
return false;
}
for (quint32 i = 0; i < numberOfKeys; ++i) {
QByteArray publicKey;
if (!stream.readString(publicKey)) {
m_error = tr("Failed to read public key: %1").arg(stream.errorString());
2017-10-29 15:17:24 +00:00
return false;
}
if (i == 0) {
BinaryStream publicStream(&publicKey);
if (!readPublic(publicStream)) {
return false;
}
}
2017-10-29 15:17:24 +00:00
}
// padded list of keys
if (!stream.readString(m_rawData)) {
m_error = tr("Corrupted key file, reading private key failed");
return false;
}
} else {
m_error = tr("Unsupported key type: %1").arg(m_rawType);
2017-10-29 15:17:24 +00:00
return false;
}
// load private if no encryption
if (!encrypted()) {
return openKey();
} else {
m_comment = tr("(encrypted)");
2017-10-29 15:17:24 +00:00
}
return true;
}
bool OpenSSHKey::encrypted() const
{
return (m_cipherName != "none");
}
bool OpenSSHKey::openKey(const QString& passphrase)
2017-10-29 15:17:24 +00:00
{
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
QScopedPointer<SymmetricCipher> cipher(new SymmetricCipher());
2017-10-29 15:17:24 +00:00
if (!m_rawPrivateData.isEmpty()) {
2017-10-29 15:17:24 +00:00
return true;
}
if (m_rawData.isEmpty()) {
2017-10-29 15:17:24 +00:00
m_error = tr("No private key payload to decrypt");
return false;
}
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
QByteArray rawData = m_rawData;
2017-10-29 15:17:24 +00:00
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
if (m_cipherName != "none") {
QString l_cipherName(m_cipherName);
if (l_cipherName.endsWith(OPENSSH_CIPHER_SUFFIX)) {
l_cipherName.remove(OPENSSH_CIPHER_SUFFIX);
}
auto cipherMode = SymmetricCipher::stringToMode(l_cipherName);
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
if (cipherMode == SymmetricCipher::InvalidMode) {
m_error = tr("Unknown cipher: %1").arg(l_cipherName);
return false;
} else if (cipherMode == SymmetricCipher::Aes256_GCM) {
m_error = tr("AES-256/GCM is currently not supported");
2017-10-29 15:17:24 +00:00
return false;
}
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
QByteArray keyData, ivData;
2017-10-29 15:17:24 +00:00
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
if (m_kdfName == "bcrypt") {
if (passphrase.isEmpty()) {
m_error = tr("Passphrase is required to decrypt this key");
return false;
}
2017-10-29 15:17:24 +00:00
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
int keySize = cipher->keySize(cipherMode);
int ivSize = cipher->ivSize(cipherMode);
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
BinaryStream optionStream(&m_kdfOptions);
QByteArray salt;
quint32 rounds;
optionStream.readString(salt);
optionStream.read(rounds);
QByteArray decryptKey(keySize + ivSize, '\0');
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
try {
auto baPass = passphrase.toUtf8();
auto pwhash = Botan::PasswordHashFamily::create_or_throw("Bcrypt-PBKDF")->from_iterations(rounds);
pwhash->derive_key(reinterpret_cast<uint8_t*>(decryptKey.data()),
decryptKey.size(),
baPass.constData(),
baPass.size(),
reinterpret_cast<const uint8_t*>(salt.constData()),
salt.size());
} catch (std::exception& e) {
m_error = tr("Key derivation failed: %1").arg(e.what());
return false;
}
2017-10-29 15:17:24 +00:00
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
keyData = decryptKey.left(keySize);
ivData = decryptKey.right(ivSize);
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
} else if (m_kdfName == "md5") {
if (m_cipherIV.length() < 8) {
m_error = tr("Cipher IV is too short for MD5 kdf");
return false;
}
2017-10-29 15:17:24 +00:00
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
int keySize = cipher->keySize(cipherMode);
QByteArray mdBuf;
do {
QCryptographicHash hash(QCryptographicHash::Md5);
hash.addData(mdBuf);
hash.addData(passphrase.toUtf8());
hash.addData(m_cipherIV.data(), 8);
mdBuf = hash.result();
keyData.append(mdBuf);
} while (keyData.size() < keySize);
if (keyData.size() > keySize) {
// If our key size isn't a multiple of 16 (e.g. AES-192 or something),
// then we will need to truncate it.
keyData.resize(keySize);
}
2017-10-29 15:17:24 +00:00
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
ivData = m_cipherIV;
} else if (m_kdfName != "none") {
m_error = tr("Unknown KDF: %1").arg(m_kdfName);
2017-10-29 15:17:24 +00:00
return false;
}
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
// Initialize the cipher using the processed key and iv data
if (!cipher->init(cipherMode, SymmetricCipher::Decrypt, keyData, ivData)) {
m_error = tr("Failed to initialize cipher: %1").arg(cipher->errorString());
return false;
}
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
// Decrypt the raw data, we do not use finish because padding is handled separately
if (!cipher->process(rawData)) {
m_error = tr("Decryption failed: %1").arg(cipher->errorString());
2017-10-29 15:17:24 +00:00
return false;
}
}
if (m_rawType == TYPE_DSA_PRIVATE) {
if (!ASN1Key::parseDSA(rawData, *this)) {
m_error = tr("Decryption failed, wrong passphrase?");
return false;
}
return true;
} else if (m_rawType == TYPE_RSA_PRIVATE) {
Replace all crypto libraries with Botan Selected the [Botan crypto library](https://github.com/randombit/botan) due to its feature list, maintainer support, availability across all deployment platforms, and ease of use. Also evaluated Crypto++ as a viable candidate, but the additional features of Botan (PKCS#11, TPM, etc) won out. The random number generator received a backend upgrade. Botan prefers hardware-based RNG's and will provide one if available. This is transparent to KeePassXC and a significant improvement over gcrypt. Replaced Argon2 library with built-in Botan implementation that supports i, d, and id. This requires Botan 2.11.0 or higher. Also simplified the parameter test across KDF's. Aligned SymmetricCipher parameters with available modes. All encrypt and decrypt operations are done in-place instead of returning new objects. This allows use of secure vectors in the future with no additional overhead. Took this opportunity to decouple KeeShare from SSH Agent. Removed leftover code from OpenSSHKey and consolidated the SSH Agent code into the same directory. Removed bcrypt and blowfish inserts since they are provided by Botan. Additionally simplified KeeShare settings interface by removing raw certificate byte data from the user interface. KeeShare will be further refactored in a future PR. NOTE: This PR breaks backwards compatibility with KeeShare certificates due to different RSA key storage with Botan. As a result, new "own" certificates will need to be generated and trust re-established. Removed YKChallengeResponseKeyCLI in favor of just using the original implementation with signal/slots. Removed TestRandom stub since it was just faking random numbers and not actually using the backend. TestRandomGenerator now uses the actual RNG. Greatly simplified Secret Service plugin's use of crypto functions with Botan.
2021-04-04 12:56:00 +00:00
if (!ASN1Key::parseRSA(rawData, *this)) {
m_error = tr("Decryption failed, wrong passphrase?");
return false;
}
return true;
} else if (m_rawType == TYPE_OPENSSH_PRIVATE) {
BinaryStream keyStream(&rawData);
2017-10-29 15:17:24 +00:00
quint32 checkInt1;
quint32 checkInt2;
2017-10-29 15:17:24 +00:00
keyStream.read(checkInt1);
keyStream.read(checkInt2);
if (checkInt1 != checkInt2) {
m_error = tr("Decryption failed, wrong passphrase?");
return false;
}
m_check = checkInt1;
return readPrivate(keyStream);
2017-10-29 15:17:24 +00:00
}
m_error = tr("Unsupported key type: %1").arg(m_rawType);
return false;
2017-10-29 15:17:24 +00:00
}
bool OpenSSHKey::readKeyParts(BinaryStream& in, const QList<KeyPart> parts, BinaryStream& out)
{
for (auto part : parts) {
switch (part) {
case STR_PART: {
QByteArray t;
if (!in.readString(t)) {
m_error = tr("Unexpected EOF while reading key");
return false;
}
out.writeString(t);
break;
}
case UINT8_PART: {
quint8 i;
if (!in.read(i)) {
m_error = tr("Unexpected EOF while reading key");
return false;
}
out.write(i);
break;
}
default:
m_error = tr("Unsupported key part");
return false;
}
}
return true;
}
2017-10-29 15:17:24 +00:00
bool OpenSSHKey::readPublic(BinaryStream& stream)
{
// clang-format off
static const QMap<QString, QList<KeyPart>> keyTemplates {
{ "ssh-dss", {STR_PART, STR_PART, STR_PART, STR_PART} },
{ "ssh-rsa", {STR_PART, STR_PART} },
{ "ecdsa-sha2-nistp256", {STR_PART, STR_PART} },
{ "ecdsa-sha2-nistp384", {STR_PART, STR_PART} },
{ "ecdsa-sha2-nistp521", {STR_PART, STR_PART} },
{ "ssh-ed25519", {STR_PART} },
{ "sk-ecdsa-sha2-nistp256@openssh.com", {STR_PART, STR_PART, STR_PART} },
{ "sk-ssh-ed25519@openssh.com", {STR_PART, STR_PART} },
};
// clang-format on
m_rawPublicData.clear();
BinaryStream rawPublicDataStream(&m_rawPublicData);
2017-10-29 15:17:24 +00:00
if (!stream.readString(m_type)) {
m_error = tr("Unexpected EOF while reading public key");
return false;
}
if (!keyTemplates.contains(m_type)) {
2018-02-06 17:22:21 +00:00
m_error = tr("Unknown key type: %1").arg(m_type);
2017-10-29 15:17:24 +00:00
return false;
}
return readKeyParts(stream, keyTemplates[m_type], rawPublicDataStream);
2017-10-29 15:17:24 +00:00
}
bool OpenSSHKey::readPrivate(BinaryStream& stream)
{
// clang-format off
static const QMap<QString, QList<KeyPart>> keyTemplates {
{ "ssh-dss", {STR_PART, STR_PART, STR_PART, STR_PART, STR_PART} },
{ "ssh-rsa", {STR_PART, STR_PART, STR_PART, STR_PART, STR_PART, STR_PART} },
{ "ecdsa-sha2-nistp256", {STR_PART, STR_PART, STR_PART} },
{ "ecdsa-sha2-nistp384", {STR_PART, STR_PART, STR_PART} },
{ "ecdsa-sha2-nistp521", {STR_PART, STR_PART, STR_PART} },
{ "ssh-ed25519", {STR_PART, STR_PART} },
{ "sk-ecdsa-sha2-nistp256@openssh.com", {STR_PART, STR_PART, STR_PART, UINT8_PART, STR_PART, STR_PART} },
{ "sk-ssh-ed25519@openssh.com", {STR_PART, STR_PART, UINT8_PART, STR_PART, STR_PART} },
};
// clang-format on
m_rawPrivateData.clear();
BinaryStream rawPrivateDataStream(&m_rawPrivateData);
2017-10-29 15:17:24 +00:00
if (!stream.readString(m_type)) {
m_error = tr("Unexpected EOF while reading private key");
return false;
}
if (!keyTemplates.contains(m_type)) {
2018-02-06 17:22:21 +00:00
m_error = tr("Unknown key type: %1").arg(m_type);
2017-10-29 15:17:24 +00:00
return false;
}
if (!readKeyParts(stream, keyTemplates[m_type], rawPrivateDataStream)) {
m_error = tr("Unexpected EOF while reading private key");
return false;
2017-10-29 15:17:24 +00:00
}
if (!stream.readString(m_comment)) {
m_error = tr("Unexpected EOF while reading private key");
return false;
}
return true;
}
bool OpenSSHKey::writePublic(BinaryStream& stream)
{
if (m_rawPublicData.isEmpty()) {
2017-10-29 15:17:24 +00:00
m_error = tr("Can't write public key as it is empty");
return false;
}
if (!stream.writeString(m_type)) {
m_error = tr("Unexpected EOF when writing public key");
return false;
}
if (!stream.write(m_rawPublicData)) {
m_error = tr("Unexpected EOF when writing public key");
return false;
2017-10-29 15:17:24 +00:00
}
return true;
}
bool OpenSSHKey::writePrivate(BinaryStream& stream)
{
if (m_rawPrivateData.isEmpty()) {
2017-10-29 15:17:24 +00:00
m_error = tr("Can't write private key as it is empty");
return false;
}
if (!stream.writeString(m_type)) {
m_error = tr("Unexpected EOF when writing private key");
return false;
}
if (!stream.write(m_rawPrivateData)) {
m_error = tr("Unexpected EOF when writing private key");
return false;
2017-10-29 15:17:24 +00:00
}
if (!stream.writeString(m_comment)) {
m_error = tr("Unexpected EOF when writing private key");
return false;
}
return true;
}
bool OpenSSHKey::parseCertificate(QByteArray& data)
{
QString stringData = QString::fromLatin1(data);
QStringList elements = stringData.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts);
QStringList certificateTypeList = {
"ssh-ed25519-cert-v01@openssh.com",
"ssh-rsa-cert-v01@openssh.com",
"ssh-dss-cert-v01@openssh.com",
"sk-ssh-ed25519-cert-v01@openssh.com",
"sk-ssh-rsa-cert-v01@openssh.com",
"sk-ssh-dss-cert-v01@openssh.com",
"rsa-sha2-256-cert-v01@openssh.com",
"sk-rsa-sha2-256-cert-v01@openssh.com",
"rsa-sha2-512-cert-v01@openssh.com",
"sk-rsa-sha2-512-cert-v01@openssh.com",
"ecdsa-sha2-nistp256-cert-v01@openssh.com",
"sk-ecdsa-sha2-nistp256-cert-v01@openssh.com",
"ecdsa-sha2-nistp384-cert-v01@openssh.com",
"sk-ecdsa-sha2-nistp384-cert-v01@openssh.com",
"ecdsa-sha2-nistp521-cert-v01@openssh.com",
"sk-ecdsa-sha2-nistp521-cert-v01@openssh.com",
};
if(elements.isEmpty() || elements.size() < 2 || !certificateTypeList.contains(elements.first())) {
m_error = tr("Invalid or unsupported certificate file");
return false;
}
m_certificateType = elements.first();
m_rawCertificateData = QByteArray::fromBase64(elements[1].toLatin1());
if (m_rawCertificateData.isEmpty()) {
m_error = tr("Base64 decoding failed");
return false;
}
return true;
}
bool OpenSSHKey::writeCertificate(BinaryStream& stream, const bool addCertificate)
{
if (m_rawCertificateData.isEmpty()) {
m_error = tr("Can't write certificate as it is empty");
return false;
}
if (!addCertificate) {
if (!stream.writeString(m_rawCertificateData)) {
m_error = tr("Unexpected EOF when writing certificate");
return false;
}
return true;
}
if (!stream.writeString(m_certificateType)) {
m_error = tr("Unexpected EOF when writing certificate");
return false;
}
if (!stream.writeString(m_rawCertificateData)) {
m_error = tr("Unexpected EOF when writing certificate");
return false;
}
if (!stream.write(m_rawPrivateData)) {
m_error = tr("Unexpected EOF when writing certificate");
return false;
}
if (!stream.writeString(m_comment)) {
m_error = tr("Unexpected EOF when writing certificate");
return false;
}
return true;
}
2017-10-29 15:17:24 +00:00
uint qHash(const OpenSSHKey& key)
{
return qHash(key.fingerprint());
}