bool avjackif::async_register_new_user(std::string user_name, boost::asio::yield_context yield_context) { // 先发 client_hello if( m_shared_key.empty()) async_client_hello(yield_context); auto digest = EVP_sha1(); // 先生成 RSA 密钥 _rsa.reset(RSA_generate_key(2048, 65537, 0, 0), RSA_free); // 然后生成 CSR boost::shared_ptr<X509_REQ> csr(X509_REQ_new(), X509_REQ_free); boost::shared_ptr<EVP_PKEY> pkey(EVP_PKEY_new(), EVP_PKEY_free); EVP_PKEY_set1_RSA(pkey.get(), _rsa.get()); // 添加证书申请信息 auto subj =X509_REQ_get_subject_name(csr.get()); /* X509_NAME_add_entry_by_NID(subj, NID_countryName, "CN"); X509_NAME_add_entry_by_NID(subj, NID_stateOrProvinceName, "Shanghai"); X509_NAME_add_entry_by_NID(subj, NID_localityName, "Shanghai"); X509_NAME_add_entry_by_NID(subj, NID_organizationName, "avplayer"); X509_NAME_add_entry_by_NID(subj, NID_organizationalUnitName, "sales"); */ X509_NAME_add_entry_by_NID(subj, NID_commonName, user_name); // X509_NAME_add_entry_by_NID(subj, NID_pkcs9_emailAddress, "test-client"); X509_REQ_set_pubkey(csr.get(), pkey.get()); // 签出 CSR X509_REQ_sign(csr.get(), pkey.get(), digest); unsigned char * out = NULL; auto csr_out_len = i2d_X509_REQ(csr.get(), &out); std::string csrout((char*)out, csr_out_len); OPENSSL_free(out); out = NULL; auto rsa_key_out_len = i2d_RSA_PUBKEY(_rsa.get(), &out); std::string rsa_key((char*)out, rsa_key_out_len); OPENSSL_free(out); PEM_write_X509_REQ(stderr, csr.get()); // 然后发送 注册信息 proto::user_register user_register; user_register.set_user_name(user_name); user_register.set_rsa_pubkey(rsa_key); user_register.set_csr(csrout); boost::asio::async_write(*m_sock, boost::asio::buffer(av_router::encode(user_register)), yield_context); // 读取应答 std::unique_ptr<proto::user_register_result> user_register_result((proto::user_register_result*)async_read_protobuf_message(*m_sock, yield_context)); return user_register_result->result() == proto::user_register_result::REGISTER_SUCCEED; }
/* decrypts the RSA encrypted text read from the XML file, * and saves the AES key and the other needed info * uses libgcrypt for decryption */ int AESKey::decryptRSA( string s_cipher_text_b64 ) { RSAKey rsa_key( this->p_demux ); unsigned char *ps_cipher_text = NULL; unsigned char *ps_plain_text = NULL; gcry_mpi_t cipher_text_mpi = NULL; gcry_sexp_t cipher_text_sexp = NULL; gcry_sexp_t plain_text_sexp = NULL; gcry_mpi_t plain_text_mpi = NULL; gcry_sexp_t tmp_sexp = NULL; gcry_error_t err; size_t length; int i_ret = VLC_EGENERIC; /* get RSA private key file path */ if( rsa_key.setPath() ) goto end; /* read private key from file */ if( rsa_key.readPEM() ) goto end; /* remove spaces and newlines from encoded cipher text * (usually added for indentation in XML files) * */ try { s_cipher_text_b64.erase( remove_if( s_cipher_text_b64.begin(), s_cipher_text_b64.end(), static_cast<int(*)(int)>(isspace) ), s_cipher_text_b64.end() ); } catch( ... ) { msg_Err( this->p_demux, "error while handling string" ); goto end; } /* decode cipher from BASE64 to binary */ if( ! ( length = vlc_b64_decode_binary( &ps_cipher_text, s_cipher_text_b64.c_str() ) ) ) { msg_Err( this->p_demux, "could not decode cipher from Base64" ); goto end; } /* initialize libgcrypt */ vlc_gcrypt_init (); /* create S-expression for ciphertext */ if( ( err = gcry_mpi_scan( &cipher_text_mpi, GCRYMPI_FMT_USG, ps_cipher_text, 256, NULL ) ) ) { msg_Err( this->p_demux, "could not scan MPI from cipher text: %s", gcry_strerror( err ) ); goto end; } if( ( err = gcry_sexp_build( &cipher_text_sexp, NULL, "(enc-val(flags oaep)(rsa(a %m)))", cipher_text_mpi ) ) ) { msg_Err( this->p_demux, "could not build S-expression for cipher text: %s", gcry_strerror( err ) ); goto end; } /* decrypt */ if( ( err = gcry_pk_decrypt( &plain_text_sexp, cipher_text_sexp, rsa_key.priv_key ) ) ) { msg_Err( this->p_demux, "error while decrypting RSA encrypted info: %s", gcry_strerror( err ) ); goto end; } /* extract plain-text from S-expression */ if( ! ( tmp_sexp = gcry_sexp_find_token( plain_text_sexp, "value", 0 ) ) ) /* when using padding flags, the decrypted S-expression is of the form * "(value <plaintext>)", where <plaintext> is an MPI */ { msg_Err( this->p_demux, "decrypted text is in an unexpected form; decryption may have failed" ); goto end; } /* we could have used the gcry_sexp_nth_data to get the data directly, * but as that function is newly introduced (libgcrypt v1.6), * we prefer compatibility, even though that means passing the data through an MPI first */ if( ! ( plain_text_mpi = gcry_sexp_nth_mpi( tmp_sexp, 1, GCRYMPI_FMT_USG ) ) ) { msg_Err( this->p_demux, "could not extract MPI from decrypted S-expression" ); goto end; } if( ( err = gcry_mpi_aprint( GCRYMPI_FMT_USG, &ps_plain_text, &length, plain_text_mpi ) ) ) { msg_Err( this->p_demux, "error while extracting plain text from MPI: %s", gcry_strerror( err ) ); goto end; } /* interpret the plaintext data */ switch( length ) { case 138: /* SMPTE DCP */ if( this->extractInfo( ps_plain_text, true ) ) goto end; break; case 134: /* Interop DCP */ if( this->extractInfo( ps_plain_text, false ) ) goto end; break; case -1: msg_Err( this->p_demux, "could not decrypt" ); goto end; default: msg_Err( this->p_demux, "CipherValue field length does not match SMPTE nor Interop standards" ); goto end; } i_ret = VLC_SUCCESS; end: free( ps_cipher_text ); gcry_mpi_release( cipher_text_mpi ); gcry_sexp_release( cipher_text_sexp ); gcry_sexp_release( plain_text_sexp ); gcry_mpi_release( plain_text_mpi ); gcry_sexp_release( tmp_sexp ); gcry_free( ps_plain_text ); return i_ret; }
rsa_key rsa_key::take_ownership(pointer _ptr) { throw_error_if_not(_ptr); return rsa_key(_ptr, deleter); }