Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
TSSH_HOST="127.0.0.1"
TSSH_PORT="1022"
TSSH_USERNAME="admin"
TSSH_PASSWORD="123456"
5 changes: 5 additions & 0 deletions .ide/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# .ide/Dockerfile

FROM cnbcool/default-dev-env:latest

RUN apt-get update && apt-get install -y g++ libssl-dev strace make libtool autoconf automake tcpdump
38 changes: 38 additions & 0 deletions README.dev.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@

### 测试


生成 SSH 私钥和公钥
```bash
docker run --rm -it --entrypoint /keygen.sh linuxserver/openssh-server
```

启动 openssh-server

```bash
docker run -d \
--name=openssh-server \
--hostname=openssh-server `#optional` \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=Etc/UTC \
-e PUBLIC_KEY=yourpublickey `#optional` \
-e PUBLIC_KEY_FILE=/path/to/file `#optional` \
-e PUBLIC_KEY_DIR=/path/to/directory/containing/_only_/pubkeys `#optional` \
-e PUBLIC_KEY_URL=https://github.com/username.keys `#optional` \
-e SUDO_ACCESS=false `#optional` \
-e PASSWORD_ACCESS=false `#optional` \
-e USER_PASSWORD=password `#optional` \
-e USER_PASSWORD_FILE=/path/to/file `#optional` \
-e USER_NAME=linuxserver.io `#optional` \
-e LOG_STDOUT= `#optional` \
-p 2222:2222 \
-v /path/to/openssh-server/config:/config \
--restart unless-stopped \
lscr.io/linuxserver/openssh-server:latest
```

```bash
#!/bin/bash
docker run -d --name ssh-server -p 1022:2222 -e SUDO_ACCESS=true -e USER_NAME=admin -e PASSWORD_ACCESS=true -e USER_PASSWORD=123456 lscr.io/linuxserver/openssh-server
```
13 changes: 13 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

set -e

make -f makefile.dist

./configure

# ./configure WITH_LTO=yes

make clean
make

25 changes: 25 additions & 0 deletions include/Crypto.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,20 @@ namespace crypto {
size_t getDhHashSize(void) const noexcept override;
};

class CryptoEcdhSha2Nistp256 final : public CryptoDH{
private:
size_t sha256Len;

public:
CryptoEcdhSha2Nistp256(void);
~CryptoEcdhSha2Nistp256(void) override;
void dhHash(std::vector<uint8_t>& buff,
std::vector<uint8_t>& hash) const noexcept override;
void dhHash(std::vector<uint8_t>& buff,
uint8_t* hash) const noexcept override;
size_t getDhHashSize(void) const noexcept override;
};

class CryptoHKeyAlg{
public:
virtual ~CryptoHKeyAlg(void) = 0;
Expand Down Expand Up @@ -294,6 +308,7 @@ namespace crypto {
CryptoMacStC* macStC;
CryptoBlkEncCtS* blkEncCtS;
CryptoBlkEncStC* blkEncStC;
bool ecdhKex;

const std::vector<std::string> clientHKeyAlg,
clientKexAlg,
Expand Down Expand Up @@ -328,6 +343,10 @@ namespace crypto {
langCtSString,
langStCString;

EVP_PKEY* ecdhPkey;
EVP_PKEY* ecdhPeerKey;
std::vector<uint8_t> ecdhQc;

void setHKeyAlg(void) anyexcept;
size_t setKexAlg(void) anyexcept;
void setMacAlgCtS(size_t idx) anyexcept;
Expand Down Expand Up @@ -399,6 +418,12 @@ namespace crypto {
std::vector<uint8_t>& iv) const anyexcept;
void serverKeyHash(const conceptsLib::ConstantIterable auto& in,
std::vector<uint8_t> &out) const anyexcept;
bool isEcdhKex(void) const noexcept;
void ecdhGenKey(std::vector<uint8_t>& pubKey) anyexcept;
void ecdhSetPeerKey(const std::vector<uint8_t>& peerKey) anyexcept;
void ecdhGetSharedKey(std::vector<uint8_t>& shared) anyexcept;
const std::vector<uint8_t>&
getEcdhQc(void) const noexcept;
};

extern template
Expand Down
7 changes: 7 additions & 0 deletions include/Tssh.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ enum STATUS { SSH_CONN_START = 0,
SSH_MSG_SERVICE_REQUEST = 5, SSH_MSG_SERVICE_ACCEPT = 6,
SSH_DISCONNECT_BY_APPLICATION = 11, SSH_MSG_KEXINIT = 20,
SSH_MSG_NEWKEYS = 21, SSH_MSG_KEX_DH_GEX_REQUEST_OLD = 30,
SSH_MSG_KEX_ECDH_REPLY = 31,
SSH_MSG_USERAUTH_REQUEST = 50, SSH_MSG_USERAUTH_FAILURE = 51,
SSH_MSG_USERAUTH_SUCCESS = 52, SSH_MSG_USERAUTH_BANNER = 53,
SSH_MSG_USERAUTH_INFO_REQUEST = 60, SSH_MSG_USERAUTH_INFO_RESPONSE = 61,
Expand Down Expand Up @@ -282,6 +283,7 @@ namespace tssh{
struct termios termOld,
termNew;
std::string knownHosts;
bool ecdhMode;

void readSsh(void) anyexcept;
bool readSshEnc(int chan=-1) anyexcept;
Expand All @@ -296,17 +298,22 @@ namespace tssh{
std::vector<uint8_t>& setKexMsg(void) anyexcept;
void checkServerAlgList(void) anyexcept;
void checkServerDhReply(void) anyexcept;
void checkServerEcdhReply(void) anyexcept;
void checkServerSignature(void) anyexcept;
void createKeys(size_t keyLen) anyexcept;
const std::string& getServerId(void) const noexcept;
const std::string& getClientId(void) const noexcept;
void getStatistics(void) const noexcept;
uint8_t getLastPacketType(void) const noexcept;
uint32_t getSndCount(void) const noexcept;
uint32_t getRcvCount(void) const noexcept;
void addHeader(uint8_t packetType,
std::vector<uint8_t>& buff) const anyexcept;
void sendWithHeader(std::vector<uint8_t>& buff,
uint8_t allign) const anyexcept;
void createSendPacket(const uint8_t packetType,
std::initializer_list<VarData*>&& list) anyexcept;
void resetSshCounters(void) noexcept;
};

using StatusTree = std::map<unsigned int, std::set<unsigned int>>;
Expand Down
11 changes: 11 additions & 0 deletions run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

set -e

chmod +x ./src/tssh

source .env
set +a

# ./src/tssh -p $TSSH_PORT -l "$TSSH_USERNAME" -d "$TSSH_HOST"
./src/tssh -p $TSSH_PORT -l "$TSSH_USERNAME" "$TSSH_HOST"
165 changes: 160 additions & 5 deletions src/CryptoImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,9 @@ namespace crypto{
Crypto::Crypto(void) :
kexalg(nullptr), hKeyalg(nullptr), macCtS(nullptr),
macStC(nullptr), blkEncCtS(nullptr), blkEncStC(nullptr),
ecdhKex(false), ecdhPkey(nullptr), ecdhPeerKey(nullptr),
clientHKeyAlg { "rsa-sha2-256", "ssh-rsa" },
clientKexAlg { "diffie-hellman-group14-sha256", "diffie-hellman-group14-sha1"},
clientKexAlg { "ecdh-sha2-nistp256", "diffie-hellman-group14-sha256", "diffie-hellman-group14-sha1"},
clientMacCtSAlg { "hmac-sha2-256", "hmac-sha1"},
clientMacStCAlg { "hmac-sha2-256", "hmac-sha1"},
clientBlkEncStCAlg { "aes128-ctr" },
Expand Down Expand Up @@ -159,6 +160,9 @@ namespace crypto{
delete blkEncCtS;
delete blkEncStC;

EVP_PKEY_free(ecdhPkey);
EVP_PKEY_free(ecdhPeerKey);

EVP_cleanup();
ERR_free_strings();
ERR_remove_state(0);
Expand Down Expand Up @@ -300,6 +304,134 @@ namespace crypto{
return hKeyalg->getDhDescr();;
}

bool Crypto::isEcdhKex(void) const noexcept{
return ecdhKex;
}

void Crypto::ecdhGenKey(vector<uint8_t>& pubKey) anyexcept{
EVP_PKEY_CTX* pctx { EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr) };
if(pctx == nullptr)
throw CryptoException(string("ecdhGenKey: EVP_PKEY_CTX_new_id failed: ") +
ERR_error_string(ERR_get_error(), nullptr));

if(EVP_PKEY_keygen_init(pctx) != 1){
EVP_PKEY_CTX_free(pctx);
throw CryptoException(string("ecdhGenKey: EVP_PKEY_keygen_init failed: ") +
ERR_error_string(ERR_get_error(), nullptr));
}

if(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1) != 1){
EVP_PKEY_CTX_free(pctx);
throw CryptoException(string("ecdhGenKey: set_ec_paramgen_curve_nid failed: ") +
ERR_error_string(ERR_get_error(), nullptr));
}

if(EVP_PKEY_keygen(pctx, &ecdhPkey) != 1){
EVP_PKEY_CTX_free(pctx);
throw CryptoException(string("ecdhGenKey: EVP_PKEY_keygen failed: ") +
ERR_error_string(ERR_get_error(), nullptr));
}
EVP_PKEY_CTX_free(pctx);

// Encode public key as uncompressed EC point (0x04 + x + y)
size_t pubLen { 0 };
if(EVP_PKEY_get_octet_string_param(ecdhPkey, "pub", nullptr, 0, &pubLen) != 1)
throw CryptoException(string("ecdhGenKey: get pub len failed: ") +
ERR_error_string(ERR_get_error(), nullptr));

pubKey.resize(pubLen);
if(EVP_PKEY_get_octet_string_param(ecdhPkey, "pub", pubKey.data(), pubLen, &pubLen) != 1)
throw CryptoException(string("ecdhGenKey: get pub failed: ") +
ERR_error_string(ERR_get_error(), nullptr));

ecdhQc = pubKey;
TRACE("* ECDH Generated Q_C: ", &pubKey);
}

void Crypto::ecdhSetPeerKey(const vector<uint8_t>& peerKey) anyexcept{
// Create EC_KEY from the peer's uncompressed point
EC_KEY* ecKey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if(ecKey == nullptr)
throw CryptoException(string("ecdhSetPeerKey: EC_KEY_new_by_curve_name failed: ") +
ERR_error_string(ERR_get_error(), nullptr));

const unsigned char* pdata = peerKey.data();
EC_POINT* point = EC_POINT_new(EC_KEY_get0_group(ecKey));
if(point == nullptr){
EC_KEY_free(ecKey);
throw CryptoException("ecdhSetPeerKey: EC_POINT_new failed.");
}

if(EC_POINT_oct2point(EC_KEY_get0_group(ecKey), point, pdata, peerKey.size(), nullptr) != 1){
EC_POINT_free(point);
EC_KEY_free(ecKey);
throw CryptoException(string("ecdhSetPeerKey: EC_POINT_oct2point failed: ") +
ERR_error_string(ERR_get_error(), nullptr));
}

if(EC_KEY_set_public_key(ecKey, point) != 1){
EC_POINT_free(point);
EC_KEY_free(ecKey);
throw CryptoException(string("ecdhSetPeerKey: EC_KEY_set_public_key failed: ") +
ERR_error_string(ERR_get_error(), nullptr));
}
EC_POINT_free(point);

ecdhPeerKey = EVP_PKEY_new();
if(ecdhPeerKey == nullptr){
EC_KEY_free(ecKey);
throw CryptoException("ecdhSetPeerKey: EVP_PKEY_new failed.");
}

if(EVP_PKEY_assign_EC_KEY(ecdhPeerKey, ecKey) != 1){
EC_KEY_free(ecKey);
throw CryptoException(string("ecdhSetPeerKey: EVP_PKEY_assign_EC_KEY failed: ") +
ERR_error_string(ERR_get_error(), nullptr));
}

TRACE("* ECDH Set Peer Q_S: ", &peerKey);
}

void Crypto::ecdhGetSharedKey(vector<uint8_t>& shared) anyexcept{
EVP_PKEY_CTX* pctx { EVP_PKEY_CTX_new(ecdhPkey, nullptr) };
if(pctx == nullptr)
throw CryptoException(string("ecdhGetSharedKey: CTX_new failed: ") +
ERR_error_string(ERR_get_error(), nullptr));

if(EVP_PKEY_derive_init(pctx) != 1){
EVP_PKEY_CTX_free(pctx);
throw CryptoException(string("ecdhGetSharedKey: derive_init failed: ") +
ERR_error_string(ERR_get_error(), nullptr));
}

if(EVP_PKEY_derive_set_peer(pctx, ecdhPeerKey) != 1){
EVP_PKEY_CTX_free(pctx);
throw CryptoException(string("ecdhGetSharedKey: derive_set_peer failed: ") +
ERR_error_string(ERR_get_error(), nullptr));
}

size_t sharedLen { 0 };
if(EVP_PKEY_derive(pctx, nullptr, &sharedLen) != 1){
EVP_PKEY_CTX_free(pctx);
throw CryptoException(string("ecdhGetSharedKey: derive (len) failed: ") +
ERR_error_string(ERR_get_error(), nullptr));
}

shared.resize(sharedLen);
if(EVP_PKEY_derive(pctx, shared.data(), &sharedLen) != 1){
EVP_PKEY_CTX_free(pctx);
throw CryptoException(string("ecdhGetSharedKey: derive failed: ") +
ERR_error_string(ERR_get_error(), nullptr));
}
EVP_PKEY_CTX_free(pctx);

TRACE("* ECDH Shared Key: ", &shared);
}

const vector<uint8_t>& Crypto::getEcdhQc(void) const noexcept{
return ecdhQc;
}

BIGNUM* Crypto::getE(void) const noexcept{
return hKeyalg->getE();
}
Expand All @@ -317,7 +449,7 @@ namespace crypto{
size_t idx { 0 };
for(auto i {clientKexAlg.cbegin()}; i != clientKexAlg.cend(); ++i){
if(serverKexAlg->find(*i) != serverKexAlg->end()){
found = true;
found = true;
break;
}
idx++;
Expand All @@ -327,12 +459,17 @@ namespace crypto{

switch(idx){
case 0:
kexalg = new CryptoDHG14Sha256();
TRACE("* DH Selected: diffie-hellman-group14-sha256");
kexalg = new CryptoEcdhSha2Nistp256();
ecdhKex = true;
TRACE("* KEX Selected: ecdh-sha2-nistp256");
break;
case 1:
kexalg = new CryptoDHG14Sha256();
TRACE("* KEX Selected: diffie-hellman-group14-sha256");
break;
case 2:
kexalg = new CryptoDHG14Sha1();
TRACE("* DH Selected: diffie-hellman-group14-sha1");
TRACE("* KEX Selected: diffie-hellman-group14-sha1");
break;
default:
throw CryptoException("setKexAlg: Unsupported DH algorithm.");
Expand Down Expand Up @@ -546,6 +683,24 @@ namespace crypto{
return sha256Len;
}

CryptoEcdhSha2Nistp256::CryptoEcdhSha2Nistp256(void)
: sha256Len {SHA256_DIGEST_LENGTH}
{}

CryptoEcdhSha2Nistp256::~CryptoEcdhSha2Nistp256(void){ }

void CryptoEcdhSha2Nistp256::dhHash(vector<uint8_t>& buff, vector<uint8_t>& hash) const noexcept{
static_cast<void>(SHA256(buff.data(), buff.size(), hash.data()));
}

void CryptoEcdhSha2Nistp256::dhHash(vector<uint8_t>& buff, uint8_t* hash) const noexcept{
static_cast<void>(SHA256(buff.data(), buff.size(), hash));
}

size_t CryptoEcdhSha2Nistp256::getDhHashSize(void) const noexcept{
return sha256Len;
}

CryptoKeyRsa::CryptoKeyRsa(string ids) : keyFilePrefix("id_rsa"), nullKey("FFFFFFFF"),
id(ids), descr("RSA")
{
Expand Down
Loading