LCOV - code coverage report
Current view: top level - src/crypto - crypto.cc (source / functions) Hit Total Coverage
Test: mosh-1.3.2 Code Coverage Lines: 116 134 86.6 %
Date: 2022-02-06 20:19:53 Functions: 16 16 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :     Mosh: the mobile shell
       3             :     Copyright 2012 Keith Winstein
       4             : 
       5             :     This program is free software: you can redistribute it and/or modify
       6             :     it under the terms of the GNU General Public License as published by
       7             :     the Free Software Foundation, either version 3 of the License, or
       8             :     (at your option) any later version.
       9             : 
      10             :     This program is distributed in the hope that it will be useful,
      11             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :     GNU General Public License for more details.
      14             : 
      15             :     You should have received a copy of the GNU General Public License
      16             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17             : 
      18             :     In addition, as a special exception, the copyright holders give
      19             :     permission to link the code of portions of this program with the
      20             :     OpenSSL library under certain conditions as described in each
      21             :     individual source file, and distribute linked combinations including
      22             :     the two.
      23             : 
      24             :     You must obey the GNU General Public License in all respects for all
      25             :     of the code used other than OpenSSL. If you modify file(s) with this
      26             :     exception, you may extend this exception to your version of the
      27             :     file(s), but you are not obligated to do so. If you do not wish to do
      28             :     so, delete this exception statement from your version. If you delete
      29             :     this exception statement from all source files in the program, then
      30             :     also delete it here.
      31             : */
      32             : 
      33             : #include <string.h>
      34             : #include <stdio.h>
      35             : #include <errno.h>
      36             : #include <stdlib.h>
      37             : #include <assert.h>
      38             : #include <sys/resource.h>
      39             : #include <fstream>
      40             : 
      41             : #include "byteorder.h"
      42             : #include "crypto.h"
      43             : #include "base64.h"
      44             : #include "fatal_assert.h"
      45             : #include "prng.h"
      46             : 
      47             : using namespace Crypto;
      48             : 
      49         452 : long int myatoi( const char *str )
      50             : {
      51         452 :   char *end;
      52             : 
      53         452 :   errno = 0;
      54         452 :   long int ret = strtol( str, &end, 10 );
      55             : 
      56         452 :   if ( ( errno != 0 )
      57         452 :        || ( end != str + strlen( str ) ) ) {
      58           0 :     throw CryptoException( "Bad integer." );
      59             :   }
      60             : 
      61         452 :   return ret;
      62             : }
      63             : 
      64     8005333 : uint64_t Crypto::unique( void )
      65             : {
      66     8005333 :   static uint64_t counter = 0;
      67     8005333 :   uint64_t rv = counter++;
      68     8005333 :   if ( counter == 0 ) {
      69           0 :     throw CryptoException( "Counter wrapped", true );
      70             :   }
      71     8005333 :   return rv;
      72             : }
      73             : 
      74       13590 : AlignedBuffer::AlignedBuffer( size_t len, const char *data )
      75       13590 :   : m_len( len ), m_allocated( NULL ), m_data( NULL )
      76             : {
      77       13590 :   size_t alloc_len = len ? len : 1;
      78             : #if defined(HAVE_POSIX_MEMALIGN)
      79       13590 :   if ( ( 0 != posix_memalign( &m_allocated, 16, alloc_len ) )
      80       13590 :       || ( m_allocated == NULL ) ) {
      81           0 :     throw std::bad_alloc();
      82             :   }
      83       13590 :   m_data = (char *) m_allocated;
      84             : 
      85             : #else
      86             :   /* malloc() a region 15 bytes larger than we need, and find
      87             :      the aligned offset within. */
      88             :   m_allocated = malloc( 15 + alloc_len );
      89             :   if ( m_allocated == NULL ) {
      90             :     throw std::bad_alloc();
      91             :   }
      92             : 
      93             :   uintptr_t iptr = (uintptr_t) m_allocated;
      94             :   if ( iptr & 0xF ) {
      95             :     iptr += 16 - ( iptr & 0xF );
      96             :   }
      97             :   assert( !( iptr & 0xF ) );
      98             :   assert( iptr >= (uintptr_t) m_allocated );
      99             :   assert( iptr <= ( 15 + (uintptr_t) m_allocated ) );
     100             : 
     101             :   m_data = (char *) iptr;
     102             : 
     103             : #endif /* !defined(HAVE_POSIX_MEMALIGN) */
     104             : 
     105       13590 :   if ( data ) {
     106        2900 :     memcpy( m_data, data, len );
     107             :   }
     108       13590 : }
     109             : 
     110      262592 : Base64Key::Base64Key( string printable_key )
     111             : {
     112      262592 :   if ( printable_key.length() != 22 ) {
     113           0 :     throw CryptoException( "Key must be 22 letters long." );
     114             :   }
     115             : 
     116      262592 :   string base64 = printable_key + "==";
     117             : 
     118      262592 :   size_t len = 16;
     119      262592 :   if ( !base64_decode( base64.data(), 24, key, &len ) ) {
     120           0 :     throw CryptoException( "Key must be well-formed base64." );
     121             :   }
     122             : 
     123      262592 :   if ( len != 16 ) {
     124           0 :     throw CryptoException( "Key must represent 16 octets." );
     125             :   }
     126             : 
     127             :   /* to catch changes after the first 128 bits */
     128      525184 :   if ( printable_key != this->printable_key() ) {
     129           0 :     throw CryptoException( "Base64 key was not encoded 128-bit key." );
     130             :   }
     131      262592 : }
     132             : 
     133         580 : Base64Key::Base64Key()
     134             : {
     135         580 :   PRNG().fill( key, sizeof( key ) );
     136         580 : }
     137             : 
     138      262144 : Base64Key::Base64Key(PRNG &prng)
     139             : {
     140      262144 :   prng.fill( key, sizeof( key ) );
     141      262144 : }
     142             : 
     143     1049476 : string Base64Key::printable_key( void ) const
     144             : {
     145     1049476 :   char base64[ 24 ];
     146             :   
     147     1049476 :   base64_encode( key, 16, base64, 24 );
     148             : 
     149     1049476 :   if ( (base64[ 23 ] != '=')
     150     1049476 :        || (base64[ 22 ] != '=') ) {
     151           0 :     throw CryptoException( string( "Unexpected output from base64_encode: " ) + string( base64, 24 ) );
     152             :   }
     153             : 
     154     1049476 :   base64[ 22 ] = 0;
     155     1049476 :   return string( base64 );
     156             : }
     157             : 
     158        1156 : Session::Session( Base64Key s_key )
     159        1156 :   : key( s_key ), ctx_buf( ae_ctx_sizeof() ),
     160        1156 :     ctx( (ae_ctx *)ctx_buf.data() ), blocks_encrypted( 0 ),
     161        1156 :     plaintext_buffer( RECEIVE_MTU ),
     162        1156 :     ciphertext_buffer( RECEIVE_MTU ),
     163        1156 :     nonce_buffer( Nonce::NONCE_LEN )
     164             : {
     165        1156 :   if ( AE_SUCCESS != ae_init( ctx, key.data(), 16, 12, 16 ) ) {
     166           0 :     throw CryptoException( "Could not initialize AES-OCB context." );
     167             :   }
     168        1156 : }
     169             : 
     170        1608 : Session::~Session()
     171             : {
     172        1608 :   fatal_assert( ae_clear( ctx ) == AE_SUCCESS );
     173        1608 : }
     174             : 
     175     8038101 : Nonce::Nonce( uint64_t val )
     176             : {
     177     8038101 :   uint64_t val_net = htobe64( val );
     178             : 
     179     8038101 :   memset( bytes, 0, 4 );
     180     8038101 :   memcpy( bytes + 4, &val_net, 8 );
     181     8038101 : }
     182             : 
     183     8076106 : uint64_t Nonce::val( void ) const
     184             : {
     185     8076106 :   uint64_t ret;
     186     8076106 :   memcpy( &ret, bytes + 4, 8 );
     187     8076106 :   return be64toh( ret );
     188             : }
     189             : 
     190       40066 : Nonce::Nonce( const char *s_bytes, size_t len )
     191             : {
     192       40066 :   if ( len != 8 ) {
     193           0 :     throw CryptoException( "Nonce representation must be 8 octets long." );
     194             :   }
     195             : 
     196       40066 :   memset( bytes, 0, 4 );
     197       40066 :   memcpy( bytes + 4, s_bytes, 8 );
     198       40066 : }
     199             : 
     200       38101 : const string Session::encrypt( const Message & plaintext )
     201             : {
     202       38101 :   const size_t pt_len = plaintext.text.size();
     203       38101 :   const int ciphertext_len = pt_len + 16;
     204             : 
     205       38101 :   assert( (size_t)ciphertext_len <= ciphertext_buffer.len() );
     206       38101 :   assert( pt_len <= plaintext_buffer.len() );
     207             : 
     208       38101 :   memcpy( plaintext_buffer.data(), plaintext.text.data(), pt_len );
     209       38101 :   memcpy( nonce_buffer.data(), plaintext.nonce.data(), Nonce::NONCE_LEN );
     210             : 
     211       38101 :   if ( ciphertext_len != ae_encrypt( ctx,                                     /* ctx */
     212       38101 :                                      nonce_buffer.data(),                     /* nonce */
     213       38101 :                                      plaintext_buffer.data(),                 /* pt */
     214             :                                      pt_len,                                  /* pt_len */
     215             :                                      NULL,                                    /* ad */
     216             :                                      0,                                       /* ad_len */
     217       38101 :                                      ciphertext_buffer.data(),                /* ct */
     218             :                                      NULL,                                    /* tag */
     219             :                                      AE_FINALIZE ) ) {                        /* final */
     220           0 :     throw CryptoException( "ae_encrypt() returned error." );
     221             :   }
     222             : 
     223       38101 :   blocks_encrypted += pt_len >> 4;
     224       38101 :   if ( pt_len & 0xF ) {
     225             :     /* partial block */
     226       35615 :     blocks_encrypted++;
     227             :   }
     228             : 
     229             :   /* "Both the privacy and the authenticity properties of OCB degrade as
     230             :       per s^2 / 2^128, where s is the total number of blocks that the
     231             :       adversary acquires.... In order to ensure that s^2 / 2^128 remains
     232             :       small, a given key should be used to encrypt at most 2^48 blocks (2^55
     233             :       bits or 4 petabytes)"
     234             : 
     235             :      -- http://tools.ietf.org/html/draft-krovetz-ocb-03
     236             : 
     237             :      We deem it unlikely that a legitimate user will send 4 PB through a Mosh
     238             :      session.  If it happens, we simply kill the session.  The server and
     239             :      client use the same key, so we actually need to die after 2^47 blocks.
     240             :   */
     241       38101 :   if ( blocks_encrypted >> 47 ) {
     242           0 :     throw CryptoException( "Encrypted 2^47 blocks.", true );
     243             :   }
     244             : 
     245       38101 :   string text( ciphertext_buffer.data(), ciphertext_len );
     246             : 
     247      114303 :   return plaintext.nonce.cc_str() + text;
     248       38101 : }
     249             : 
     250       40086 : const Message Session::decrypt( const char *str, size_t len )
     251             : {
     252       40086 :   if ( len < 24 ) {
     253          40 :     throw CryptoException( "Ciphertext must contain nonce and tag." );
     254             :   }
     255             : 
     256       40066 :   int body_len = len - 8;
     257       40066 :   int pt_len = body_len - 16;
     258             : 
     259       40066 :   if ( pt_len < 0 ) { /* super-assertion that pt_len does not equal AE_INVALID */
     260           0 :     fprintf( stderr, "BUG.\n" );
     261           0 :     exit( 1 );
     262             :   }
     263             : 
     264       40066 :   assert( (size_t)body_len <= ciphertext_buffer.len() );
     265       40066 :   assert( (size_t)pt_len <= plaintext_buffer.len() );
     266             : 
     267       40066 :   Nonce nonce( str, 8 );
     268       40066 :   memcpy( ciphertext_buffer.data(), str + 8, body_len );
     269       40066 :   memcpy( nonce_buffer.data(), nonce.data(), Nonce::NONCE_LEN );
     270             : 
     271       40066 :   if ( pt_len != ae_decrypt( ctx,                      /* ctx */
     272       40066 :                              nonce_buffer.data(),      /* nonce */
     273       40066 :                              ciphertext_buffer.data(), /* ct */
     274             :                              body_len,                 /* ct_len */
     275             :                              NULL,                     /* ad */
     276             :                              0,                        /* ad_len */
     277       40066 :                              plaintext_buffer.data(),  /* pt */
     278             :                              NULL,                     /* tag */
     279             :                              AE_FINALIZE ) ) {         /* final */
     280        4026 :     throw CryptoException( "Packet failed integrity check." );
     281             :   }
     282             : 
     283       38053 :   const Message ret( nonce, string( plaintext_buffer.data(), pt_len ) );
     284             : 
     285       38053 :   return ret;
     286             : }
     287             : 
     288             : static rlim_t saved_core_rlimit;
     289             : 
     290             : /* Disable dumping core, as a precaution to avoid saving sensitive data
     291             :    to disk. */
     292        1352 : void Crypto::disable_dumping_core( void ) {
     293        1352 :   struct rlimit limit;
     294        1352 :   if ( 0 != getrlimit( RLIMIT_CORE, &limit ) ) {
     295             :     /* We don't throw CryptoException because this is called very early
     296             :        in main(), outside of 'try'. */
     297           0 :     perror( "getrlimit(RLIMIT_CORE)" );
     298           0 :     exit( 1 );
     299             :   }
     300             : 
     301        1352 :   saved_core_rlimit = limit.rlim_cur;
     302        1352 :   limit.rlim_cur = 0;
     303        1352 :   if ( 0 != setrlimit( RLIMIT_CORE, &limit ) ) {
     304           0 :     perror( "setrlimit(RLIMIT_CORE)" );
     305           0 :     exit( 1 );
     306             :   }
     307        1352 : }
     308             : 
     309         452 : void Crypto::reenable_dumping_core( void ) {
     310             :   /* Silent failure is safe. */
     311         452 :   struct rlimit limit;
     312         452 :   if ( 0 == getrlimit( RLIMIT_CORE, &limit ) ) {
     313         452 :     limit.rlim_cur = saved_core_rlimit;
     314         452 :     setrlimit( RLIMIT_CORE, &limit );
     315             :   }
     316         452 : }

Generated by: LCOV version 1.14