static jint socket_read (JNIEnv *env, jobject object, jobject fileDescriptor) { int fd; int err; if (fileDescriptor == NULL) { jniThrowNullPointerException(env, NULL); return (jint)-1; } fd = jniGetFDFromFileDescriptor(env, fileDescriptor); if (env->ExceptionCheck()) { return (jint)0; } unsigned char buf; err = socket_read_all(env, object, fd, &buf, 1); if (err < 0) { jniThrowIOException(env, errno); return (jint)0; } if (err == 0) { // end of file return (jint)-1; } return (jint)buf; }
static jint socket_readba (JNIEnv *env, jobject object, jbyteArray buffer, jint off, jint len, jobject fileDescriptor) { int fd; jbyte* byteBuffer; int ret; if (fileDescriptor == NULL || buffer == NULL) { jniThrowNullPointerException(env, NULL); return (jint)-1; } if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) { jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); return (jint)-1; } if (len == 0) { // because socket_read_all returns 0 on EOF return 0; } fd = jniGetFDFromFileDescriptor(env, fileDescriptor); if (env->ExceptionCheck()) { return (jint)-1; } byteBuffer = env->GetByteArrayElements(buffer, NULL); if (NULL == byteBuffer) { // an exception will have been thrown return (jint)-1; } ret = socket_read_all(env, object, fd, byteBuffer + off, len); // A return of -1 above means an exception is pending env->ReleaseByteArrayElements(buffer, byteBuffer, 0); return (jint) ((ret == 0) ? -1 : ret); }
static int psync_p2p_download(psync_socket_t sock, psync_fileid_t fileid, const unsigned char *filehashhex, uint64_t fsize, const char *filename){ uint32_t keylen, enctype; psync_symmetric_key_t key; psync_encrypted_symmetric_key_t ekey; psync_crypto_aes256_ctr_encoder_decoder_t decoder; psync_hash_ctx hashctx; uint64_t off; size_t rd; psync_file_t fd; unsigned char buff[4096]; unsigned char hashbin[PSYNC_HASH_DIGEST_LEN], hashhex[PSYNC_HASH_DIGEST_HEXLEN]; if (unlikely_log(socket_read_all(sock, &keylen, sizeof(keylen)) || socket_read_all(sock, &enctype, sizeof(enctype)))) return PSYNC_NET_TEMPFAIL; if (enctype!=P2P_ENCTYPE_RSA_AES){ debug(D_ERROR, "unknown encryption type %u", (unsigned)enctype); return PSYNC_NET_PERMFAIL; } if (keylen>PSYNC_P2P_RSA_SIZE/8*2){ /* PSYNC_P2P_RSA_SIZE/8 is enough actually */ debug(D_ERROR, "too long key - %u bytes", (unsigned)keylen); return PSYNC_NET_PERMFAIL; } ekey=psync_ssl_alloc_encrypted_symmetric_key(keylen); if (unlikely_log(socket_read_all(sock, ekey->data, keylen)) || unlikely_log((key=psync_ssl_rsa_decrypt_symmetric_key(psync_rsa_private, ekey))==PSYNC_INVALID_SYM_KEY)){ psync_free(ekey); return PSYNC_NET_TEMPFAIL; } psync_free(ekey); decoder=psync_crypto_aes256_ctr_encoder_decoder_create(key); psync_ssl_free_symmetric_key(key); if (decoder==PSYNC_CRYPTO_INVALID_ENCODER) return PSYNC_NET_PERMFAIL; fd=psync_file_open(filename, P_O_WRONLY, P_O_CREAT|P_O_TRUNC); if (unlikely(fd==INVALID_HANDLE_VALUE)){ psync_crypto_aes256_ctr_encoder_decoder_free(decoder); debug(D_ERROR, "could not open %s", filename); return PSYNC_NET_PERMFAIL; } off=0; psync_hash_init(&hashctx); while (off<fsize){ if (fsize-off>sizeof(buff)) rd=sizeof(buff); else rd=fsize-off; if (unlikely_log(socket_read_all(sock, buff, rd))) goto err0; psync_crypto_aes256_ctr_encode_decode_inplace(decoder, buff, rd, off); if (unlikely_log(psync_file_write(fd, buff, rd)!=rd)) goto err0; psync_hash_update(&hashctx, buff, rd); off+=rd; } psync_crypto_aes256_ctr_encoder_decoder_free(decoder); psync_file_close(fd); psync_hash_final(hashbin, &hashctx); psync_binhex(hashhex, hashbin, PSYNC_HASH_DIGEST_LEN); debug(D_NOTICE, "downloaded file %s from peer", filename); if (memcmp(hashhex, filehashhex, PSYNC_HASH_DIGEST_HEXLEN)){ /* it is better to return permanent fail and let the block checksum algo to find bad blocks */ debug(D_WARNING, "got bad checksum for file %s", filename); return PSYNC_NET_PERMFAIL; } else return PSYNC_NET_OK; err0: psync_crypto_aes256_ctr_encoder_decoder_free(decoder); psync_file_close(fd); psync_hash_final(hashbin, &hashctx); return PSYNC_NET_TEMPFAIL; }
static void psync_p2p_tcphandler(void *ptr){ packet_get packet; psync_fileid_t localfileid; psync_binary_rsa_key_t binpubrsa; psync_rsa_publickey_t pubrsa; psync_symmetric_key_t aeskey; psync_encrypted_symmetric_key_t encaeskey; psync_crypto_aes256_ctr_encoder_decoder_t encoder; char *token, *localpath; uint64_t off; size_t rd; psync_socket_t sock; psync_file_t fd; uint32_t keylen, enctype; unsigned char hashhex[PSYNC_HASH_DIGEST_HEXLEN], buff[4096]; sock=*((psync_socket_t *)ptr); psync_free(ptr); debug(D_NOTICE, "got tcp connection"); if (unlikely_log(socket_read_all(sock, &packet, sizeof(packet)))) goto err0; if (unlikely_log(packet.keylen>PSYNC_P2P_RSA_SIZE) || unlikely_log(packet.tokenlen>512)) /* lets allow 8 times larger keys than we use */ goto err0; localfileid=psync_p2p_has_file(packet.hashstart, packet.genhash, packet.rand, packet.filesize, hashhex); if (!localfileid){ debug(D_WARNING, "got request for file that we do not have"); goto err0; } binpubrsa=psync_ssl_alloc_binary_rsa(packet.keylen); if (unlikely_log(socket_read_all(sock, binpubrsa->data, binpubrsa->datalen))){ psync_free(binpubrsa); goto err0; } token=psync_new_cnt(char, packet.tokenlen); if (unlikely_log(socket_read_all(sock, token, packet.tokenlen)) || unlikely_log(!check_token(token, packet.tokenlen, binpubrsa->data, packet.keylen, hashhex))){ psync_free(binpubrsa); psync_free(token); goto err0; } psync_free(token); pubrsa=psync_ssl_rsa_binary_to_public(binpubrsa); psync_free(binpubrsa); if (unlikely_log(pubrsa==PSYNC_INVALID_RSA)) goto err0; localpath=psync_local_path_for_local_file(localfileid, NULL); if (unlikely_log(!localpath)) goto err0; fd=psync_file_open(localpath, P_O_RDONLY, 0); debug(D_NOTICE, "sending file %s to peer", localpath); psync_free(localpath); if (fd==INVALID_HANDLE_VALUE){ debug(D_WARNING, "could not open local file %lu", (unsigned long)localfileid); goto err0; } aeskey=psync_crypto_aes256_ctr_gen_key(); encaeskey=psync_ssl_rsa_encrypt_symmetric_key(pubrsa, aeskey); encoder=psync_crypto_aes256_ctr_encoder_decoder_create(aeskey); psync_ssl_free_symmetric_key(aeskey); keylen=encaeskey->datalen; enctype=P2P_ENCTYPE_RSA_AES; if (unlikely_log(encaeskey==PSYNC_INVALID_ENC_SYM_KEY) || unlikely_log(encoder==PSYNC_CRYPTO_INVALID_ENCODER) || unlikely_log(socket_write_all(sock, &keylen, sizeof(keylen)) || socket_write_all(sock, &enctype, sizeof(enctype)) || socket_write_all(sock, encaeskey->data, encaeskey->datalen))){ if (encaeskey!=PSYNC_INVALID_ENC_SYM_KEY) psync_free(encaeskey); if (encoder!=PSYNC_CRYPTO_INVALID_ENCODER) psync_crypto_aes256_ctr_encoder_decoder_free(encoder); psync_file_close(fd); goto err0; } psync_free(encaeskey); off=0; while (off<packet.filesize){ if (packet.filesize-off<sizeof(buff)) rd=packet.filesize-off; else rd=sizeof(buff); if (unlikely_log(psync_file_read(fd, buff, rd)!=rd)) break; psync_crypto_aes256_ctr_encode_decode_inplace(encoder, buff, rd, off); if (unlikely_log(socket_write_all(sock, buff, rd))) break; off+=rd; } psync_crypto_aes256_ctr_encoder_decoder_free(encoder); psync_file_close(fd); debug(D_NOTICE, "file sent successfuly"); err0: psync_close_socket(sock); }