Skip to content

GenaroNetwork/libgenaro-java

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

libgenaro-java (SHIL)

Build Status

Asynchronous Java library and CLI for encrypted file transfer on the Genaro network written in Java 8. It's Compatible with libgenaro.

Features

  • Load wallet from json file with password
  • Use wallet to sign request for user authentication
  • Delete bucket/rename bucket/list buckets/list files/delete file/upload file/download file
  • Asynchronous I/O with concurrent peer-to-peer network requests for shards
  • Erasure encoding with reed solomon for data reliability
  • File encryption with AES-256-CTR
  • File name and bucket name encryption with AES-256-GCM
  • Asynchronous progress updates
  • Retry several times when upload/download is failed
  • Seed based file encryption key for portability between devices
  • File integrity and authenticity verified with HMAC-SHA512
  • Proxy support
  • Exchange report with bridge
  • File encryption key can be provided to decrypt encrypted file
  • Command line interface
  • Mock bridge and farmer, and continous integration
  • String literal can be encrypted with AES-256-CTR and directly stored to a bucket

Issues

  • Upload or download file of large size(>512MB) will not use Reed-Solomon algorithm, or it may cause an OutOfMemoryError, becasue the JavaReedSolomon library doesn't support memory mapped files.

3rd party dependencies

Package

Gradle

on Linux/Mac:

./gradlew clean build

on Windows:

gradlew clean build

or if you want to use your local gradle:

gradle clean build

Maven

mvn clean package

or if you don't want to run the tests:

mvn clean package -Dmaven.test.skip=true

PS: Will not package org.bouncycastle for signature issue.

Used as 3rd party package

Add Genaro package(genaro-sdk-x.xx.jar) to your classpath, and make sure package org.bouncycastle(bcprov-jdk15on-x.xx.jar) is in the same directory with Genaro package.

APIs

/**
 * @brief Get Genaro bridge API information.
 *
 * @return The Genaro bridge API information.
 */
public String getInfo()

/**
 * @brief List available buckets for a user.
 *
 * @param[in] callback The callback when complete
 * @return A CompletableFuture.
 */
public CompletableFuture<Void> getBuckets(final GetBucketsCallback callback)

/**
 * @brief Delete a bucket.
 *
 * @param[in] bucketId The bucket id
 * @param[in] callback The callback when complete
 * @return A CompletableFuture.
 */
public CompletableFuture<Void> deleteBucket(final String bucketId, final DeleteBucketCallback callback)

/**
 * @brief Rename a bucket.
 *
 * @param[in] bucketId The bucket id
 * @param[in] callback The callback when complete
 * @return A CompletableFuture.
 */
public CompletableFuture<Void> renameBucket(final String bucketId, final String name, final RenameBucketCallback callback)

/**
 * @brief Get a list of all files in a bucket.
 *
 * @param[in] bucketId The bucket id
 * @param[in] callback The callback when complete
 * @return A CompletableFuture.
 */
public CompletableFuture<Void> listFiles(final String bucketId, final ListFilesCallback callback)

/**
 * @brief Get mirror data for a file.
 *
 * @param[in] bucketId The bucket id
 * @param[in] fileId The file id
 * @param[in] callback The callback when complete
 * @return A CompletableFuture.
 */
public CompletableFuture<Void> listMirrors(final String bucketId, final String fileId, final ListMirrorsCallback callback)

/**
 * @brief Delete a file in a bucket.
 *
 * @param[in] bucketId The bucket id
 * @param[in] fileId The file id
 * @param[in] callback The callback when complete
 * @return A CompletableFuture.
 */
public CompletableFuture<Void> deleteFile(final String bucketId, final String fileId, final DeleteFileCallback callback)

/**
 * @brief Download a file
 *
 * @param[in] bucketId The bucket id
 * @param[in] fileId The file id
 * @param[in] filePath The file path
 * @param[in] overwrite Whether to overwrite if exists
 * @param[in] key The key of AES for decryption
 * @param[in] ctr The ctr of AES for decryption
 * @param[in] isDecrypt Whether to decrypt the downloaded data
 * @param[in] callback The callback on progress or when complete
 * @return A Downloader.
 */
public Downloader resolveFile(final String bucketId, final String fileId, final String filePath, final boolean overwrite, final boolean isDecrypt, final String keyBase16, final String ctrBase16, final ResolveFileCallback callback) throws GenaroException

/**
 * @brief Upload a file
 *
 * @param[in] rs Whether to use Reed-Solomon to generate parity shards
 * @param[in] fileOrData The file path or the text
 * @param[in] isFilePath Whether fileOrData is file path or text
 * @param[in] fileName The file name
 * @param[in] bucketId The bucket id
 * @param[in] ei The encryption info for file encryption and decryption(can be generated by function generateEncryptionInfo)
 * @param[in] callback The callback on progress or when complete
 * @return A Uploader.
 */
public Uploader storeFile(final boolean rs, final String filePath, final String fileName, final String bucketId, EncryptionInfo ei, final StoreFileCallback callback) throws GenaroException

/**
 * @brief Decrypt a file
 *
 * @param[in] filePath The undecrypted file path
 * @param[in] key The key of AES
 * @param[in] iv The ctr of AES
 * @return The decrypted text.
 */
public static String decryptFileToText(String filePath, byte[] key, byte[] iv) throws GenaroException

/**
 * @brief Encrypt the meta use AES-256-GCM combined with HMAC-SHA512 to filePath
 *
 * @param[in] meta The meta to be decrypted
 * @param[in] filePath The file path
 */
public void encryptMetaToFile(String meta, String filePath) throws GenaroException

/**
 * @brief Decrypt the meta in filePath use AES-256-GCM combined with HMAC-SHA512
 *
 * @param[in] filePath The file path
 * @return The decrypted meta.
 */
public String decryptMetaFromFile(String filePath) throws GenaroException

Example Usage

Initialize:

String bridgeUrl = "http://47.100.33.60:8080";
String V3JSON = "{ \"address\": \"aaad65391d2d2eafda9b2732000001d52a6a3dc8\",
        \"crypto\": { \"cipher\": \"aes-128-ctr\",
        \"ciphertext\": \"e968751f3d60827b6e6000006c024ecc82f33a6c55428be33249c83edba444ca\",
        \"cipherparams\": { \"iv\": \"e80d9ec9b00000a143c756ec78066ad9\" }, \"kdf\": \"scrypt\",
        \"kdfparams\": { \"dklen\": 32, \"n\": 262144, \"p\": 1, \"r\": 8, \"salt\":
        \"ea7cb2b004db67d000003790caced7a96b636762f280b243e794fb5bef8ef74b\" },
        \"mac\": \"ceb3789e77be8f2a7ab4d000001b54e048ad3f5b080b96e07759de7442e050d2\" },
        \"id\": \"e28f31b4-1f43-428b-9b12-ab58000004b1\", \"version\": 3 }";
String passwd = "xxxxxx";
Genaro api;
try {
    api = new Genaro(bridgeUrl, V3JSON, passwd);
} catch (Exception e) {
    return;
}

List buckets:

CompletableFuture<Void> fu = api.getBuckets(new GetBucketsCallback() {
    @Override
    public void onFinish(Bucket[] buckets) { }
    @Override
    public void onFail(String error) { }
});

// getBuckets is Non-Blocking, if you want to wait until it is finished, call fu.join()

Delete bucket:

String bucketId = "5bfcf77cea9b6322c5abd929";
CompletableFuture<Void> fu = api.deleteBucket(bucketId, new DeleteBucketCallback() {
    @Override
    public void onFinish() { }
    @Override
    public void onFail(String error) { }
}));

// deleteBucket is Non-Blocking, if you want to wait until it is finished, call fu.join()

Rename bucket:

String bucketId = "5bfcf77cea9b6322c5abd929";
String newName = "abc";
CompletableFuture<Void> fu = api.renameBucket(bucketId, newName, new RenameBucketCallback() {
    @Override
    public void onFinish() { }
    @Override
    public void onFail(String error) { }
}

// renameBucket is Non-Blocking, if you want to wait until it is finished, call fu.join()

List files:

String bucketId = "5bfcf77cea9b6322c5abd929";
CompletableFuture<Void> fu = api.listFiles(bucketId, new ListFilesCallback() {
    @Override
    public void onFinish(GenaroFile[] files) { }
    @Override
    public void onFail(String error) { }
}

// listFiles is Non-Blocking, if you want to wait until it is finished, call fu.join()

Delete file:

String bucketId = "5bfcf77cea9b6322c5abd929";
String fileId = "5c0e1289bbdd6f2d157dd8b2";
CompletableFuture<Void> fu = api.deleteFile(bucketId, fileId, new DeleteFileCallback() {
    @Override
    public void onFinish() { }
    @Override
    public void onFail(String error) { }
}

// deleteFile is Non-Blocking, if you want to wait until it is finished, call fu.join()

Upload file:

String bucketId = "5bfcf4ea7991d267f4eb53b4";
String fileOrData = "xxxxxx";
boolean isFilePath = true;
String fileName = "abc.txt";
boolean rs = true;

EncryptionInfo ei = genaro.generateEncryptionInfo(null, bucketId);
Uploader uploader = null;
try {
    uploader = api.storeFile(rs, fileOrData, isFilePath, fileName, bucketId, ei, new StoreFileCallback() {
        @Override
        public void onBegin(long fileSize) { }
        @Override
        public void onProgress(float progress) { }
        @Override
        public void onCancel() { }
        @Override
        public void onFail(String error) { }
        @Override
        public void onFinish(String fileId, byte[] sha256OfEncrypted) { }
    });
} catch (GenaroException e) { }

// storeFile is Non-Blocking, if you want to wait until it is finished, call uploader.join()
// if you want to cancel it, call uploader.cancel()

Download file:

String bucketId = "5bfcf4ea7991d267f4eb53b4";
String fileId = "5c0103fd5a158a5612e67461";
String filePath = "xxxxxx";

Downloader downloader = null;
try {
    downloader = genaro.resolveFile(bucketId, fileId, path, true, true, null, null, new ResolveFileCallback() {
        @Override
        public void onBegin() { }
        @Override
        public void onProgress(float progress) { }
        @Override
        public void onCancel() { }
        @Override
        public void onFail(String error) { }
        @Override
        public void onFinish(long fileBytes, byte[] sha256) { }
    });
} catch (GenaroException e) { }

// resolveFile is Non-Blocking, if you want to wait until it is finished, call downloader.join()
// if you want to cancel it, call downloader.cancel()