SSH use and protocol analysis

xiaoxiao2021-03-06  101

SSH use and protocol analysis

Creation time: 2001-03-03

Article properties: reprint

Source: Author: yeye

Article submission:

Xundi (xundi_at_xfocus.org)

Author: yeye

Published: 11-24-2000 13:46

SSH is a toolkit used to replace Telnet, FTP, and R commands, mainly to solve the problem of password transmission in the online text. In order to system security and the rights of users themselves, it is necessary to promote SSH. SSH has two versions, and we now introduce version 2.

Install SSH

Specific steps are as follows:

Get the SSH package. (

ftp://ftp.pku.edu.cn:/pub/unix/ssh-2.3.0.tar.gz)

Become a superuser (root).

# gzip -cd ssh-2.3.0.tar.gz | TAR XVF -

# CD SSH-2.3.0

# ./configure

Note that if you want to use TCP_WrapPers to control SSH, you need to add option "--with-libwrap = / path / to / libwrap /" when configure is used to tell SSH about libwrap.a and tcpd.h.

# Make

# make install

The procedures related to SSH are placed under / usr / local / bin, including SSH, SFTP, SSHD2, SSH-KEYGEN, and the like.

Second, the configuration

The configuration file of SSH is under / etc / ssh2, including the host public key and private key of SSHD2: hostKey and HostKey.pub. These two files are usually generated automatically when installing SSH. You can re-generate them by the following command:

# r r / etc / ssh2 / hostkey *

# ssh-keygen2 -p / etc / ssh2 / hostkey

The SSH2_CONFIG file does not need to be modified in general cases.

Third, start SSHD2

Each system to use SSH must run SSHD2 in the background. Start with manual:

# / usr / local / bin / sshd2

You can add this command in "/etc/rc2.d/s99local" so that the system will automatically start SSHD2 each time you start.

Fourth, use TCP_WrapPERS to control SSH

Installing SSH sites can use TCP_WrapPers to limit which IP addresses can be accessed by SSH. For example, join in /etc/hosts.allow

sshd, sshd2: 10.0.0.1

Then only 10.0.0.1 can be accessed through SSH.

The above is all the work completed by the system administrator. Let's talk about how ordinary users use SSH.

V. Basic application

Each user must complete the following steps before using SSH:

Both the local host (for example, local.pku.edu.cn) generate its own SSH public key and private key. The command is as follows:

Local # ssh-keygen

Generating 1024-bit DSA Key Pair

1 OOO.OOO.O

Key generated.

1024-bit dsa, teng @ ns, fri oct 20 2000 17:27:05

Passphrase: *********** / * Enter your password here, and use it when you visit this host.

Again: *********** / *

Private key saved to /Home1/teng/.ssh2/ID_DSA_1024_A

Public key saved to /Home1/teng/.ssh2/ID_DSA_1024_A.PUB

The generated private key and public key (id_dsa_1024_a, and id_dsa_1024_a.pub) are stored in the ~ / .ssh2 directory of your catalog. And user-related SSH configuration files are below ~ / .ssh2. The private key is saved by the user on the local host, and the public key needs to be transferred to the ~ / .ssh2 of your own account from the remote host, if you want to access the local host with SSH2. Create a "Identification" file in ~ / .ssh2 to illustrate the private key for identity authentication. The command is as follows:

Local: ~ / .ssh2 # echo "idkey id_dsa_1024_a"> Identification

3. Similarly, the above steps are completed on a remote host (such as Remote.pku.edu.cn).

4. Yourself (Id_DSA_1024_A.PUB) copy to the remote host (Id_DSA_1024_A.PUB) of local ("teng") (here "teng") .ssh2 directory, you can name "local.pub", usually uploaded with FTP.

On the remote host, in your own directory. Ssh2 directory, create an "Authorzation" file, which specifies the public key file used to identify authentication. The command is as follows:

Remote: ~ / .ssh2 # echo "key local.pub"> Authorization

Now you can log in to the remote system from your locally. The command is as follows:

Local # ssh remote.pku.edu.cn

Passphrase for key "/home1/teng/.ssh2/ID_DSA_1024_A" with comment "1024-bit DSA,

TENG @ ns, fri oct 20 2000 17:27:05 ": ***********

At this time, you will want you to enter your SSH password (Passphrase). After verification, log in to the Remote host.

Part 1: Agreement overview

During the entire communication process, the authentication connection is achieved through the following stages.

The first stage:

TCP connection requests are issued by the client to the server. After the TCP connection is established, the client enters the waiting, the server sends the first message to the client, declares its version number, including the protocol version number and software version number. The protocol version number consists of the main version number and the secondary version number. It consists of the software version number, such as:

"SSH-

/ N "

String. The maximum length of the software version number string is 40 bytes, only for debugging. After receiving the message, the client receives a message, the content is also the version number. The client responds to the protocol version number in the message to determine: When the client's version number is lower than the version number of the server, if the client has a specific code to simulate, it sends a lower version number; if it can't Then send your own version number. When the client's version number is higher than the server version number, the client sends its own lower version number. According to the convention, if the protocol changes, the main protocol version number is constant; if it is incompatible, the primary protocol version number rises.

After receiving the protocol version number sent by the client, the server compares it to your own, decides whether to work with the client. If you can't, disconnect the TCP connection; if you can, you will send the first binary packet according to the binary packet protocol, and both parties work together with a lower protocol version. So far, these two packets are just simple strings, you and I have read them directly.

second stage:

After negotiating the solution to the version issues, both parties began to communicate with binary packets. Send the first package to the client to the client, the content is the public key portion of the Host Key, the public key portion of the RSA Service Key, supported encryption method, supported authentication method , Subordinate version logo, as well as a 64-bit random number (cookie). This package is not encrypted, which is sent to clearly. After the client receives the package, the session ID is calculated according to the two keys and 64-bit random numbers called cookies and session keys for encryption. The client will then send a package to the server, the content is the encryption method, cookie copy, client-end protocol version flag, and the public key portion of the server's host key and the public key portion of the service key. A 32-byte random string of the server calculates the session key. In addition to this 32-byte random string for the server calculation session key, the other content of this package is not encrypted. Thereafter, the communication between the two parties is encrypted, and the server issues a second package to the client (the first encrypted package in both parties) confirms that the client's package has been received.

The third phase:

The two sides then entered the certification phase. The way to choose from is:

(1) ~ / .rhosts or /etc/hosts.equiv certification (not allowable to use it when default);

(2) Improved ~ / .rhosts or /etc/hosts.equiv certification with RSA;

(3) RSA certification;

(4) Password certification.

If you are authenticated using ~ / .rhosts or /etc/hosts.equiv, the port number used by the client must be less than 1024.

The first step in the authentication is that the client sends an SSH_CMSG_USER package to the server to declares the username, the server checks if the user exists, determine if the authentication is required. If the user exists and does not require authentication, the server returns a SSH_SMSG_SUCCESS package, and the authentication is complete. Otherwise, the server will send an SSH_SMSG_FAILURE package, indicating that the user does not exist, or if you need to perform authentication. Note that if the user does not exist, the server still keeps reading any packages from the client. In addition to the type of type SSH_MSG_Disconnect, ssh_msg_ignore, and SSH_MSG_Debug, any type of package is SSH_SMSG_FAILURUR package. In this way, the client cannot determine if the user exists.

If the user exists but needs to be authenticated, the second step of entering the authentication. After the client receives the SSH_SMSG_FAILURE package sent by the server, keeps the server to apply for authentication with a variety of different ways, until the time limit has been connected to the server shutdown connection. Time limit is generally set to 5 minutes. For any application, if the server is accepted, it responds in a ssh_smsg_success package; if it is not accepted, or if it is not recognized, it responds with the ssh_smsg_failure package.

The fourth stage:

After the authentication is complete, the client submits session requests to the server. The server is waiting to process the client's request. At this stage, whether as long as the request is successfully processed, the server responds to the server to the client; otherwise responds to the SSH_SMSG_Failure package, which means that the server processing request fails, or cannot identify the request. The session request is divided into such a variety of categories: Applications for data transfer, apply for a pseudo terminal, start the X11, TCP / IP port forwarding, start the authentication agent, run the shell, execute the command. To this end, all of the previous messages require IP's service type (TOS) to use option iptos_throughput.

The fifth stage:

After the session application is successful, the connection enters the interactive session mode. In this mode, data is transmitted in both directions. At this point, the IP service type (TOS) is required to use the iptos_lowdelay option. When the server informs the client's own exit state, the interactive session mode ends. (Note: After entering the interactive session mode, the encryption is turned off. After the client sends a new session key to the server, the encryption will start. Use what method is encrypted by the client.)

Part II: Switching and Encryption of Keys

There is a host key file on the server side, which makes it like this:

1. Problem version of the private key file format;

2. Encryption type (1 byte);

3. Reserved words (4 bytes);

4. 4 bytes of unsigned integers;

5. MP integer;

6. MP integer;

7. Note the length of string;

8. Note string;

9. Check the word (4 bytes);

10. MP integer;

11. MP integer;

12. MP type integer;

13. MP integer;

The three fields of 4, 5, 6 constitute the public key portion of the host key; 10, 11, 12, 13 four fields constitute the private key portion of the host key. 9, 10, 11, 12, 13 Five Fields encrypt the encryption method of the encryption type of field 2. The four bytes of calibration word is equal, that is, the first byte is equal to the third byte, and the second byte is equal to the fourth byte. This cross-phase check is performed when the server reads this file. If this condition is not met, the error exits.

The first step of running the server program is to read the host key file according to the above field. Subsequently generate a random number, call the function

Void RSA_Generate_Key

(

RsaprivateKey * PRV,

RsapublicKey * PUB,

Randomstate * State,

Unsigned int bits

);

Generating a service key, the service key is also composed of a public key and a private key. The first pointer parameter of this function pointing to the private key portion of the service key, the second pointing to the public key portion. Then send the public key portion of the host key and the public key portion of the service key to the client. After waiting for the package that the client responds, the server is solved by the private key portion of its own host key and the private key part of the service key to obtain a 32-byte random string from the client. Then calculate your own session number, and use the first 16-byte of the 32-byte random string from the first 16-byte xor client to put it as its own session key. Note that the server calculates its session number, the public key portion of the 8 bytes, the public key portion of the host key, and the public key portion of the service key as a parameter.

Let's see the client. The first step in the client startup is also read the host key. Then wait for the server host key, service key, and 8 bytes of cookie. Note that the server sent is just the public key portion of the host key and the service key. After receiving the package, the client immediately calculates the session number as the server side from the server side. As can be seen from the above, the session number calculated by the server and the client is actually the same.

Subsequently, the client checks the user host list and system host list, check whether the host key received from the server is in the list. If not in the list, add it in the list. Then generate 32-byte random strings, this 32-byte random string is the client's session key. The client uses a 16-byte session key xor its first 16 bytes, and sends the result of the server's host key and the service key to the server after dual encryption. When generating a 32-byte random string, the random number consists of two parts, some of which are obtained from the system random number, which avoids the session key to be guess. The process of calculating session keys from the above server and client can be seen that the server and client calculated session key is the same. The above steps, summarizes that you want to exchange the determination session key, because whether it is des, IDEA, 3DES, ArcFour, or blowfish is a symmetrical encryption method, only one key, both sides know the session key to start encryption. However, the session key cannot be transferred in the network, otherwise the encryption will lose meaning. The session key is then encrypted using the RSA public key system.

The RSA public key system is to decrypt the private key with public key, which is based on such mathematical theorems:

If P, Q is different, the integer r and M satisfy

RM == 1 (MOD (P-1) (Q-1))

A is an arbitrary integer, an integer B, and C meets b == a ^ m (MOD PQ),

C == B ^ R (MOD PQ). then

c == a (MOD PQ).

The specific implementation is this:

(1) Find three positive integers p, q, r, where P, Q is different,

R is the number of mutual numbers with (P-1), (Q-1). These three numbers P, Q, R

It is a private key.

(2) Find another positive integer M satisfy the RM == 1 (MOD (P-1) (Q-1)).

Calculate n = pq, m, n is a public key.

(3) The encrypted object A is considered a positive integer and sets a = N,

A representation of A is S (S

Then separately encode each bit.

(4) Encryption: calculate B == a ^ m (MOD N) (0 <= b), B is

Encrypted results.

(5) Decryption: Calculate C == B ^ R (MOD N) (0 <= c

Decrypt results.

From the above mathematical theorem, the last result c = a.

The method and process of calculating the RSA key is to call the following function to calculate the RSA public key and the RSA private key:

____________________________________________________

Void RSA_Generate_Key

(

RsaprivateKey * PRV, RSAPUBLICKEY * PUB,

RandomState * State, Unsigned Int Bits

)

{

MP_INT TEST, AUX;

Unsigned int PBITS, QBITS;

int R;

MPZ_INIT (& PrV-> Q);

MPZ_INIT (& Prv-> P);

MPZ_INIT (& Prv-> E);

MPZ_INIT (& Prv-> D);

MPZ_INIT (& Prv-> U);

MPZ_INIT (& Prv-> n);

MPZ_INIT (& TEST);

MPZ_INIT (& AUX); / * Calculate the number of numbers p, Q * /

PBITS = BITS / 2;

PBITS = BITS - PBITS;

Retry0:

FPRINTF (stderr, "generating p:");

/ * Generate random lots p * /

RSA_Random_Prime (& Prv-> P, State, PBITS);

Retry:

FPRINTF (stderr, "generating Q:");

/ * Generate random lots q * /

RSA_Random_Prime (& Prv-> Q, State, QBITS);

/ * Judgment whether p == q, if it is returned to regenerate * /

RET = MPZ_CMP (& Prv-> P, & Prv-> Q);

IF (RET == 0)

{

FPRINTF (stderr,

"Generated the Same Prime TWICE! / N");

Goto Retry;

}

IF (RET> 0)

{

MPZ_SET (& AUX, & Prv-> P);

MPZ_SET (& Prv-> P, & Prv-> Q);

MPZ_SET (& PRV-> Q, & Aux);

}

/ * Determine P, Q is close to * /

MPZ_SUB (& Aux, & Prv-> Q, & Prv-> P);

MPZ_DIV_2EXP (& Test, & Prv-> Q, 10);

IF (MPZ_CMP (& Aux, & Test) <0)

{

FPRINTF (stderr,

"The Primes Are Too Close TOGETHER./N");

Goto Retry;

}

/ * Make Certain P and q Are Relatively Prime (In Case

One or Both WERE FALSE POSITIVES ... Though this IS

Quite impossible). * /

MPZ_GCD (& Aux, & Prv-> P, & Prv-> Q);

IF (MPZ_CMP_UI (& Aux, 1)! = 0)

{

FPRINTF (stderr,

"THE PRIMES ARE NOT Relatively Prime! / N");

Goto Retry;

}

/ * From rigor p, q export private key * /

FPRINTF (stderr, "computing the keys ... / n");

Derive_rsa_keys (& Prv-> N, & Prv-> E, & Prv-> D,

& prV-> u, & prV-> p, & prV-> q, 5);

PRV-> BITS = BITS;

/ * From the rigid number P, Q export public key * /

Pub-> bits = bits;

MPZ_INIT_SET (& Pub-> n, & prV-> n);

MPZ_INIT_SET (& Pub-> E, & Prv-> E);

/ * Test whether the public key and key are valid * /

FPRINTF (stderr, "testing the keys ... / n");

RSA_Random_INTEGER (& Test, State, Bits);

MPZ_MOD (& Test, & Test, & Pub-> n); / * must be less n. * / RSA_Private (& Aux, & Test, PRV);

RSA_PUBLIC (& Aux, & Aux, Pub);

IF (MPZ_CMP (& Aux, & Test)! = 0)

{

FPRINTF (stderr,

"**** private public failed to decrypt./N");

Goto Retry0;

}

RSA_PUBLIC (& Aux, & Test, Pub);

RSA_PRIVATE (& Aux, & Aux, PRV);

IF (MPZ_CMP (& Aux, & Test)! = 0)

{

FPRINTF (stderr,

"**** public private failed to decrypt./n");

Goto Retry0;

}

MPZ_CLEAR (& AUX);

MPZ_CLEAR (& TEST);

FPRINTF (stderr, "key generation completion./N");

}

____________________________________________________

When the function above is a pair of keys, the function is first called.

____________________________________________________

Void RSA_Random_prime

(

MP_INT * RET, RANDOMSTATE * STATE,

Unsigned int bits

)

{

MP_INT START, AUX;

Unsigned int num_primes;

Int * MODULI;

Long Difference;

MPZ_INIT (& START);

MPZ_INIT (& AUX);

Retry:

/ * Pick a random enough integer * /

RSA_Random_INTEGER (& Start, State, Bits);

/ * Set the highest two * /

MPZ_SET_UI (& Aux, 3);

MPZ_MUL_2EXP (& AUX, & AUX, BITS - 2);

MPZ_IOR (& Start, & Start, & Aux);

/ * Set the lowest two for odd numbers * /

MPZ_SET_UI (& Aux, 1);

MPZ_IOR (& Start, & Start, & Aux);

/ * Start a small number of moduli * /

MODULI = malloc (max_primes_in_table * sizeof (MODULI [0]));

IF (MODULI == NULL)

{

Printf (Stderr, "Cann't Get Memory for MODULI / N");

Exit (1);

}

IF (Bits <16)

Num_primes = 0;

/ * DON / 'T Use the Table for Very Small NumBers. * /

Else

{

For (Num_Primes = 0;

Small_primes [num_primes]! = 0; NUM_PRIMES )

{

MPZ_MOD_UI (& Aux, & Start, Small_primes [Num_Primes]);

Moduli [Num_Primes] = MPZ_GET_UI (& Aux);

}

}

/ * Look for a number, it can't be minored * /

For (Difference = 0; DIFCERENCE = 2)

{

Unsigned Int i;

IF (Difference> 0x70000000)

{

FPRINTF (stderr, "rsa_random_prime:"

"Failed to Find a Prime, Retrying./N");

IF (MODULI! = NULL)

Free (MODULI);

Else

Exit (1);

Goto Retry;

}

/ * Check if it is a small prime product * /

For (i = 0; i

{

While (MODULI [i] Difference> = small_primes [i])

MODULI [I] - = small_primes [i];

IF (MODULI [I] Difference == 0)

Break;

}

IF (i

Continue; / * Multiple of a kNown Prime. * /

/* inspection passed */

FPRINTF (stderr, ");

/ * Compute the number in questions. * /

MPZ_ADD_UI (RET, & Start, Difference);

/ * Perform The Fermat Test for Witness 2.

This Means: IT is not prime if 2 ^ n mod n! = 2. * /

MPZ_SET_UI (& Aux, 2);

MPZ_POWM (& Aux, & Aux, Ret, Ret);

IF (MPZ_CMP_UI (& Aux, 2) == 0)

{

/ * Passed The Fermat Test for Witness 2. * /

FPRINTF (stderr, " ");

/ * Perform A More Tests...................

IF (MPZ_PROBAB_PRIME_P (RET, 20))

Break; / * It is a prime with probability 1 - 2 ^ -40. * /

}

}

/ * Found A (Probable) Prime. It is in return. * /

FPRINTF (stderr, " (distance% ld) / n", DIFCERENCE);

/ * Free the small prime moduli; They Are no longer needed. * /

IF (MODULI! = NULL)

Free (MODULI);

Else

Exit (1);

/ * Sanity Check: Does Itst STILL HAVE The High Bit Set (WE Might Have

Wrapped arrone? * /

MPZ_DIV_2EXP (& Aux, RET, BITS - 1);

IF (MPZ_GET_UI (& Aux)! = 1)

{

FPRINTF (stderr,

"RSA_Random_Prime: High bit Not set, retrying./n");

Goto Retry;

}

MPZ_CLEAR (& Start);

MPZ_CLEAR (& AUX);

}

____________________________________________ randomly generate a pair of large numbers (P, Q). This is that the condition that the random large number to meet is P must be less than Q. Then call the following function to generate other groups of public key and private key pair:

Static void derive_rsa_keys

(

MP_INT * N, MP_INT * E, MP_INT * D, MP_INT * U,

MP_INT * P, MP_INT * Q,

Unsigned int eBits

)

{

MP_INT P_MINUS_1, Q_MINUS_1, AUX, PHI, G, F

ASSERT (MPZ_CMP (P, Q) <0);

MPZ_INIT (& P_MINUS_1);

MPZ_INIT (& Q_MINUS_1);

MPZ_INIT (& AUX);

MPZ_INIT (& PHI);

MPZ_INIT (& G);

MPZ_INIT (& F);

/ * Calculate P-1 and Q-1. * /

MPZ_SUB_UI (& P_minus_1, p, 1);

MPZ_SUB_UI (& Q_MINUS_1, Q, 1);

/ * pHI = (P - 1) * (q - 1) * /

MPZ_MUL (& PHI, & P_MINUS_1, & Q_MINUS_1);

/ * G is the number of "spre key set" for a given

MODULUS N. The Smaller G IS, The Better. The

Smallst G Can Get IS 2. * /

MPZ_GCD (& g, & p_minus_1, & q_minus_1);

IF (MPZ_CMP_UI (& g, 100)> = 0)

{

FPRINTF (stderr, "warning: g =");

MPZ_OUT_STR (stdout, 10, & g);

FPRINTF (stderr,

"Is Large (MANY SPARE Key Sets); Key May Be Bad! / N");

}

/ * F = phi / g; the number of relative prime

Numbers per spare key set. * /

MPZ_DIV (& F, & PHI, & G);

/ * Find A Suitable E (The public exponent). * /

MPZ_SET_UI (E, 1);

MPZ_MUL_2EXP (E, E, EBITS);

MPZ_SUB_UI (E, E, 1); / * Make Lowest Bit 1, And Substract 2. * /

/ * Keep Adding 2 Until It Is Relatively Prime

TO (P-1) (Q-1). * /

DO

{

MPZ_ADD_UI (E, E, 2);

MPZ_GCD (& Aux, E, & PHI);

}

While (MPZ_CMP_UI (& Aux, 1)! = 0);

/ * D is The Multiplicative Inverse of E, MOD F.

Could Also Be MOD (P-1) (Q-1); However, We Try To

Choose the smallest possible d. * /

MPZ_MOD_INVERSE (D, E, & F);

/ * u is The Multiplicative Inverse OF P, MOD Q,

IF P

RSA Operations Using The Chinese RemainDertheorem Method. * /

MPZ_MOD_INVERSE (U, P, Q);

/ * n = p * q (the public moduulus). * /

MPZ_MUL (N, P, Q);

/ * Clear auxiliary variables. * /

MPZ_CLEAR (& P_MINUS_1);

MPZ_CLEAR (& Q_MINUS_1);

MPZ_CLEAR (& AUX);

MPZ_CLEAR (& PHI);

MPZ_CLEAR (& G);

MPZ_CLEAR (& f);

}

____________________________________________________

Finally, for the validity of the pair of keys generated, it calls the following functions to generate a random integer.

____________________________________________________

Void RSA_Random_integer (MP_INT * RET, RandomState * State,

Unsigned int bits

{

Unsigned int Bytes = (BITS 7) / 8;

Char * str = xmalloc (bytes * 2 1);

Unsigned Int i;

/ * Generate an appropriate size 16 credit random number, convert it into an MP integer * /

For (i = 0; i

Sprintf (STR 2 * I, "% 02x", random_get_byte (state);

/ * Convert to internal representation * /

IF (MPZ_SET_STR (RET, STR, 16) <0)

{

FPRINTF ("Intenal Error, MPZ_SET_STR RETURNED ERROR");

Exit (1);

}

/ * CLEAR EXTRA DATA. * /

MEMSET (STR, 0, 2 * BYTES);

IF (str! = null)

Free (STR);

Else

Exit (1);

/ * Reduce it to the desired number of bits. * /

MPZ_MOD_2EXP (RET, RET, BITS);

}

____________________________________________________

After the service key is generated, the server sends a package to send the two key to the client, one is the public key of the host key, and the other is the public key of the service key. Follow this package with the server supported encryption type and 8 bytes, 64-bit random string cookies. The client calculates the session number based on these two key, and the session number is 16 bytes, 128 bits. The calculation method is:

Session = MD5 (host public key mode N || service public key model N || cookie)

The calculation function is:

Void Compute_Session_ID

(

Unsigned char session_id [16],

Unsigned char cookie [8],

Unsigned int host_key_bits,

MP_INT * HOST_KEY_N,

Unsigned int session_key_bits,

MP_INT * session_key_n

)

{

Unsigned int Bytes = (Host_Key_BITS 7) / 8

(session_key_bits 7) / 8 8;

Unsigned char * buf = xmalloc (bytes); struct md5context md;

MP_LINEARIZE_MSB_FIRST (BUF, Host_Key_BITS 7) / 8, Host_Key_n);

MP_LINEARIZE_MSB_FIRST (BUF (Host_Key_BITS 7) / 8,

(session_key_bits 7) / 8, session_key_n);

Memcpy (buf (host_key_bits 7) / 8 (session_key_bits 7) / 8,

Cookie, 8);

MD5init (& MD);

MD5UPDATE (& MD, BUF, BYTES);

MD5Final (session_id, & md);

Xfree (buf);

}

Void MP_LINEARIZE_MSB_FIRST

(

Unsigned char * buf, unsigned int LEN,

MP_INT * VALUE

)

{

Unsigned Int i;

MP_INT AUX;

MPZ_INIT_SET (& AUX, Value);

For (i = le; i> = 4; i - = 4)

{

Unsigned long limb = mpz_get_ui (& aux);

PUT_32BIT (BUF I - 4, LIMB);

MPZ_DIV_2exp (& Aux, & Aux, 32);

}

For (; i> 0; I -)

{

BUF [i - 1] = mpz_get_ui (& aux);

MPZ_DIV_2EXP (& Aux, & Aux, 8);

}

MPZ_CLEAR (& AUX);

}

The client calculates the session key, and the calculation process is first generated to 32 bytes, 256-bit random strings:

For (i = 0; i <32; i )

Session_key [i] = random_get_byte (state);

Then use the 16-byte session number xor this 32-word random string of the first 16 bytes of random strings, and the MSB order is arranged to constitute an MP integer:

MPZ_INIT_SET_UI (& Key, 0);

For (i = 0; i <32; i )

{

MPZ_MUL_2EXP (& Key, & Key, 8);

IF (i <16)

MPZ_ADD_UI (& Key, & Key, session_key [i] ^ session_id [i]);

Else

MPZ_ADD_UI (& Key, & Key, Session_Key [i]);

}

Send the result to the server. After the host public key and service public key is applied with the server, the client is sent to a package to the server after two RSA encryption, the client is issued. Follow this package and have a client selected encryption type. Note that at the client, it uses the original 32-byte random string session_key to be used as the session key as the session key, not the session key Key that is sent to the server. After the server is connected to the above MP integer, convert it into a 32-byte of 256-bit strings. Use the first 16-byte of the 16-byte session number XOR this string to the session key. When the server calculates its own 16-byte session number, the host public key, service public key, and 16-byte random string cookies sent to the client are also input, so it calculates the same as the client.

After this, all data transfer is encrypted with the encryption method specified by the client, encrypts the above session key. The code used in ArcFour.c, des.c, idea.c, blowfish.c. SSH claims to avoid IP spoofing, the method used in the above key exchange servers a 64-bit cookie to the client, requiring the client original copy to send back. I can't see this to avoid IP deception.

Part III: Certification

The RSA public key and the RSA private key data structure is:

Typedef struct

{

Unsigned int bits; / * modulus size * /

MP_INT E; / * Public Key Index * /

MP_INT N; / * Modulus * /

} RsapublicKey;

Typedef struct

{

Unsigned int bits; / * modulus size * /

MP_INT N; / * Modulus * /

MP_INT E; / * Public Key Index * /

MP_INT D; / * private key index * /

MP_INT U; / * MULTIPLICATIVE INVERSE OF P MOD Q. * /

MP_INT P; / * Total number P * /

MP_INT Q; / * Quality Q * /

} Rsaprivatekey;

The process of RSA certification is that the client submits an analog number member of its RSA public key to the server, and the server first reads the public key file in the user. Ssh directory for validity test, and reproduces a 256-bit binary random number cookie. Subsequently, this random number cookie was passed to the client with the public key read from the public key file. After the client received the cookie, first decrypt the private key, and then calculated 16 bytes of this cookie and session number. MD5 watermark, add two watermarks to the server. The server receives the MD5 watermark and its own watermark calculated on the cookie and the session number, if equally, the authentication is passed.

Part IV: SHELL and X11 call

An important feature provided by SSH is the X forwarding function, which can display the running results of the server-side X program in a graphic display on the client's display screen. For example, run the xterm program to start an X terminal, the X terminal window is displayed on the client's display.

Let's first look at the X window system itself. The X window system is a Unix graphical user interface (GUI), which uses the "Customer / Server" mode, and the communication between the two complies with the X protocol. Each host runs an X server and can only run an X server, but an X server can control multiple display screens (displays). Applications To make graphic display must be submitted to the X server in a customer's way, and the X server is unified to display. When the user runs the X program, it is actually calling the XOpendisPlay library function to open a PF_UNIX or TCP Socket to connect to the X server, and then submit a request to it by this connection. After the connection is established, the first thing to make in X customers is to read the display record in the user profile. Xauthority in the user's $ DISPLAY environment variable, submit the relevant content of this record to the X server for authentication. If the authentication is passed, the display request can be submitted, which is called open a X display. As a client's X program is submitted to the display request, it is actually written to the Socket that is displayed on top. When opening X is displayed, the protocol number, the authentication key (HexKey), and screen number must be provided. If the X server is not running locally, a remote host name that runs the X server is required. These are recorded in the user profile .xauthority, the protocol number, the authentication key, and the screen number are removed from this list. You can use the xauth command to view the contents of the display list: [WANGDB @ / home / wangdb]> / usr / openwin / bin / xauth list

***. ***. *** / UNIX: 10 mit-magic-cookie-1 /

92B404E556588CED6C1ACD4EBF053F68

***. ***. *** / UNIX: 11 mit-magic-cookie-1 /

92B404E556588CED6C1ACD4EBF053F68

***. ***. ***: 10 mit-magic-cookie-1 /

92B404E556588CED6C1ACD4EBF053F68

***. ***. *** / UNIX: 10 mit-magic-cookie-1 /

92B404E556588CED6C1ACD4EBF053F68

***. ***. ***: 11 mit-magic-cookie-1 /

92B404E556588CED6C1ACD4EBF053F68

***. ***. *** / UNIX: 11 mit-magic-cookie-1 /

92B404E556588CED6C1ACD4EBF053F68

[wangdb @ / home / wangdb]> Echo $ DISPLAY

***. ***. ***: 10.0

[wangdb @ / home / wangdb]> / usr / openwin / bin / xauth

Using authority file /Home/wangdb/.xauthority

XAUTH> List ***. ***. ***: 10.0

***. ***. ***: 10 mit-magic-cookie-1 /

92B404E556588CED6C1ACD4EBF053F68

XAUTH> quit

[wangdb @ / home / wangdb]>

The meaning of each field in the display record of the .xauthority file, the first field ***. ***. *** is the host name, ":" "." The front number is the X server label, "." The number behind is the display screen (display) label. This field is called a display name, and the $ DISPLAY environment variable is filled in this field. The second field is the protocol label, and the third field is a hexadecimal authentication key. The authentication key is made by the system, if the authentication key is not paired, the X server refuses to process the display request if the system is displayed. SSH implementation X forward is that the client calls the POPEN function to execute the "XAUTH LIST $ DISPLAY" command, read the screen number, protocol number, and authentication key displayed, then save the protocol number and the authentication key in memory. . The client does not send his own authentication key to the server, but generates an 8-bit binary random number, with hexadecimal printing, send this hexadecimal numeric string to the server as the authentication key. When the server is sent to open the X display request, the client uses its own real authentication key to open X display. With this method, the customer guarantees that his own certification does not disclose to the outside world, and the security is guaranteed.

After the server is connected to the client's X forward request, read the screen number, protocol number, and authentication key sent by the client, and open a socket and bind it, set it to the listening mode, and set a channel with this socket. Then, then read the X server label from the server's own profile, call the gethostname function to obtain the host name, combine the two and the customer's screen number together constitute the first field of the display list record.

When the server handles the client executes commands or starts the shell, it accepts a TCP connection with the channel set, returns a socket, and then use this socket to set a new channel. Then send a package to the client to request it to open a x display. After receiving this package, the client is connected to the local X server connection, that is, opens a X display:

___________________________________________________

INT Display_Number, SOCK;

Const char * display;

Struct sockaddr_un ssun;

/ * Try to open a socket for the local x server. * /

Display = GetENV ("Display");

IF (! display)

{

"" Display Not Set. ");

Goto fail;

}

/ * NOW WE DECODE The Value of The Display Variable

* AND Make a connection to the real x server.

* /

/ * Check if it is a unix domain socket. Unix Domain

* Displays Are in One of the Following Formats:

* UNIX: D [.s],: d [.s], :: d [.s]

* /

IF (Strncmp (Display, "UNIX:", 5) == 0 ||

Display [0] == ':')

{

/ * Connect to the unix domain socket. * /

IF (SSCANF (STRRCHR (Display, ':') 1,

"% d", & display_number! = 1)

{

ERROR ("Could Not Parse Display Number" "from Display:% .100S", DISPLAY

Goto fail;

}

/ * CREATE A Socket. * /

SOCK = Socket (AF_UNIX, SOCK_STREAM, 0);

IF (SOCK <0)

{

Error ("socket:% .100s", strerror (errno);

Goto fail;

}

/ * Connect It to the display socket. * /

ssun.sun_family = af_Unix;

#ifdef hpsux_nonstandard_x11_kludge

{

/ * HPSUX RELEASE 10.X Uses

* / VAR / Spool / Sockets / X11 / 0

* for the Unix-Domain Sockets, While Earlier

* Releases Stores The Socket in

* / usr / spool / sockets / x11 / 0

* with Soft-link from

* /TMP/.x11-unix/`Uname -n`0

* /

Struct stat st;

IF (Stat ("/ VAR / Spool / Sockets / X11", & ST) == 0)

{

Sprintf (ssun.sun_path, "% s /% d",

"/ var / spool / sockets / x11", display_number);

}

Else

{

IF (Stat ("/ usr / spool / sockets / x11", & st) == 0)

{

Sprintf (ssun.sun_path, "% s /% d",

"/ usr / spool / sockets / x11", display_number);

}

Else

{

Struct Utsname Utsbuf;

/ * HPSUX Stores Unix-Domain Sockets in

* /TMP/.x11-unix/`hostname`0

* instead of the normal /tmp/.x11-unix/x0.

* /

IF (& UTSBUF <0)

Fatal ("Uname:% .100S", STRERROR (Errno);

Sprintf (ssun.sun_path, "% .20S /%. 64S% D",

X11_Dir, utsbuf.nodeename, display_number;

}

}

}

#ELSE / * HPSUX_NONSTANDARD_X11_KLUDGE * /

{

Struct stat st;

IF (Stat ("/ VAR / X", & ST) == 0)

{

Sprintf (ssun.sun_path, "% .80s / x% d",

"/VAR/X/.x11-Unix", Display_Number;

}

ELSE IF (stat (x11_dir, & st) == 0)

{

Sprintf (ssun.sun_path, "% .80s / x% d",

X11_Dir, display_number;

}

Else

{

Sprintf (ssun.sun_path, "% .80s / x% d",

"/TMP/.x11-unix", display_number;

}

}

#ENDIF / * HPSUX_NONSTANDARD_X11_KLUDGE * / IF (Connect (Sterk, (Struct SockAddr *) & SSUN,

AF_UNIX_SIZE (SSUN)) <0)

{

Error ("Connect% .100s:% .100s",

ssun.sun_path, strrror (errno));

Close (SOCK);

Goto fail;

}

/ * OK, WE NoW everyone a connection. * /

Goto Success;

}

Success:

/ * WE HAVE SUCCESSFULLY OBTAINED A Connection TO

* The real x display.

* /

#if Defined (o_nonblock) &&! defined (o_nonblock_broken)

(void) FCNTL (SOCK, F_SETFL, O_NONBLOCK);

#ELSE / * O_NONBLOCK &&! O_NONBLOCK_BROKEN * /

(void) FCNTL (SOCK, F_SETFL, O_NDELAY);

#ENDIF / * O_NONBLOCK &&! O_nonblock_broken * /

___________________________________________________

The client then sets a new channel with this socket. Note that if the client host does not have a terminal display, in this step, it also opens a TCP Socket to the remote X server connection according to the value of your environment variable $ Display.

Final server combines the first field and the client-connected protocol number and the authentication key to form a display record, and place the user's .xauthority file. And set the value of the $ DIAPLAY environment variable to this display name of the first field.

After doing these, you can forward X forward. When the server runs the X program, use this virtual X to display the graphic display request, write the graphic display data to this virtual X display, which is written to the newly created channel to the client. After the client gets these data, it is written to the channel you just established and the X server connection, which is also submitted to the X server.

Why does the client don't directly put your own .xauthority file to the server to the server, by the server Press this record to open TCPSocket directly to the client X-established connection? The security of SSH is here, if this is done, put it completely to the outside world, and the X server itself is much more problem. The previous forged a certificate is also for this consideration, because if you know the certification key, you have a few fields in the record, it is easy to guess.

Despite these, there is still a problem. If an attacker invades or masters the host running on the SSH server, then he / she finds an SSH connection and performs an X forward service, try to obtain the connected service of the company's $ Display environment variable, and then perform the "xauth value_of_ $ display" command Also get the display record. Subsequently he / she added this record to her .xauthority file with the "XAUTH Add" command, and set their own $ DISPLAY environment variable to the display name of this record. This way he / she can run the X program during the X forward connection, and the display of the X program is all submitted to the client's X server. If the X server has a vulnerability, he / she can use it freely.

转载请注明原文地址:https://www.9cbs.com/read-124654.html

New Post(0)