{"id":21813947,"url":"https://github.com/genaronetwork/libgenaro-android","last_synced_at":"2026-05-21T05:33:14.875Z","repository":{"id":91573428,"uuid":"164846819","full_name":"GenaroNetwork/libgenaro-android","owner":"GenaroNetwork","description":null,"archived":false,"fork":false,"pushed_at":"2019-01-25T10:10:45.000Z","size":297,"stargazers_count":2,"open_issues_count":0,"forks_count":2,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-21T09:29:16.800Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GenaroNetwork.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-09T11:04:40.000Z","updated_at":"2025-02-13T16:58:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"9b9e3e23-122b-4ff4-8cbb-73848918b4e1","html_url":"https://github.com/GenaroNetwork/libgenaro-android","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/GenaroNetwork/libgenaro-android","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GenaroNetwork%2Flibgenaro-android","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GenaroNetwork%2Flibgenaro-android/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GenaroNetwork%2Flibgenaro-android/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GenaroNetwork%2Flibgenaro-android/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GenaroNetwork","download_url":"https://codeload.github.com/GenaroNetwork/libgenaro-android/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GenaroNetwork%2Flibgenaro-android/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33289860,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-21T02:57:32.698Z","status":"ssl_error","status_checked_at":"2026-05-21T02:57:31.990Z","response_time":62,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-27T14:34:31.193Z","updated_at":"2026-05-21T05:33:14.860Z","avatar_url":"https://github.com/GenaroNetwork.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# libgenaro-android\n\nAsynchronous Android library and CLI for encrypted file transfer on the Genaro network written in Java 8. It's compatible with [libgenaro](https://github.com/GenaroNetwork/libgenaro).\n\n## Features\n\n- Load wallet from json file with password\n- Use wallet to sign request for user authentication\n- Delete bucket/rename bucket/list buckets/list files/delete file/upload file/download file\n- Asynchronous I/O with concurrent peer-to-peer network requests for shards\n- Erasure encoding with reed solomon for data reliability\n- File encryption with AES-256-CTR\n- File name and bucket name encryption with AES-256-GCM\n- Asynchronous progress updates\n- Retry several times when upload/download is failed\n- Seed based file encryption key for portability between devices\n- File integrity and authenticity verified with HMAC-SHA512\n- Proxy support\n- Exchange report with bridge\n- File encryption key can be provided to decrypt encrypted file\n- Command line interface\n- Mock bridge and farmer, and continous integration\n- String literal can be encrypted with AES-256-CTR and directly stored to a bucket\n\n## Issues\n\n- Upload or download file of large size(\u003e256MB) will not use Reed-Solomon algorithm, or it may cause an OutOfMemoryError, becasue the the JavaReedSolomon library doesn't support memory mapped files.\n\n## 3rd party dependencies\n\n- [Spongy Castle](https://rtyley.github.io/spongycastle/) for crypto algorithms.\n- [dnsjava](http://www.xbill.org/dnsjava/) for base16 encoding.\n- [web3j](https://web3j.io/) for wallet managment, BIP39 and Interaction with blockchain.\n- [JavaReedSolomon](https://github.com/Backblaze/JavaReedSolomon) for reed solomon algorithm.\n- [jackson](https://github.com/FasterXML/jackson) for JSON parse/compose.\n- [okhttp3](https://github.com/square/okhttp) as HTTP client.\n- [java-getopt](https://www.urbanophile.com/arenn/hacking/download.html) a Java command line option parser that is compatible with GNU getopt.\n- [guava](https://github.com/google/guava) and [apache.commons](https://commons.apache.org/) as utility.\n- [testng](https://testng.org/doc/index.html) for testing.\n\n## Used as 3rd party package\n\n1. Import libgenaro-android as a module of your app\n\n2. Add libgenaro-android as a dependency of your app, something like: \n\n```xml\ndependencies {\n    implementation project(':libgenaro-android')\n}\n```\n\n3. Add repository for dnsjava to build.gradle of your app:\n\n```gradle\nrepositories {\n    maven { url \"http://www.jabylon.org/maven/\" }\n}\n```\n\n4. Add READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE and INTERNET permissions to AndroidManifest.xml of your app:\n\n```xml\n\u003cuses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/\u003e\n\u003cuses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/\u003e\n\u003cuses-permission android:name=\"android.permission.INTERNET\" /\u003e\n```\n\n5. Your app should request for READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permission before upload and download, such as:\n\n```java\nActivityCompat.requestPermissions(this, new String[] {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_REQUEST_CODE);\n```\n\n(PS: the JDK version of your app must be 1.8 or higher)\n\n## APIs\n\n```java\n/**\n * @brief Get Genaro bridge API information.\n *\n * @return The Genaro bridge API information.\n */\npublic String getInfo()\n\n/**\n * @brief List available buckets for a user.\n *\n * @param[in] callback The callback when complete\n * @return A CompletableFuture.\n */\npublic CompletableFuture\u003cVoid\u003e getBuckets(final GetBucketsCallback callback)\n\n/**\n * @brief Delete a bucket.\n *\n * @param[in] bucketId The bucket id\n * @param[in] callback The callback when complete\n * @return A CompletableFuture.\n */\npublic CompletableFuture\u003cVoid\u003e deleteBucket(final String bucketId, final DeleteBucketCallback callback)\n\n/**\n * @brief Rename a bucket.\n *\n * @param[in] bucketId The bucket id\n * @param[in] callback The callback when complete\n * @return A CompletableFuture.\n */\npublic CompletableFuture\u003cVoid\u003e renameBucket(final String bucketId, final String name, final RenameBucketCallback callback)\n\n/**\n * @brief Get a list of all files in a bucket.\n *\n * @param[in] bucketId The bucket id\n * @param[in] callback The callback when complete\n * @return A CompletableFuture.\n */\npublic CompletableFuture\u003cVoid\u003e listFiles(final String bucketId, final ListFilesCallback callback)\n\n/**\n * @brief Get mirror data for a file.\n *\n * @param[in] bucketId The bucket id\n * @param[in] fileId The file id\n * @param[in] callback The callback when complete\n * @return A CompletableFuture.\n */\npublic CompletableFuture\u003cVoid\u003e listMirrors(final String bucketId, final String fileId, final ListMirrorsCallback callback)\n\n/**\n * @brief Delete a file in a bucket.\n *\n * @param[in] bucketId The bucket id\n * @param[in] fileId The file id\n * @param[in] callback The callback when complete\n * @return A CompletableFuture.\n */\npublic CompletableFuture\u003cVoid\u003e deleteFile(final String bucketId, final String fileId, final DeleteFileCallback callback)\n\n/**\n * @brief Download a file\n *\n * @param[in] bucketId The bucket id\n * @param[in] fileId The file id\n * @param[in] filePath The file path\n * @param[in] overwrite Whether to overwrite if exists\n * @param[in] key The key of AES for decryption\n * @param[in] ctr The ctr of AES for decryption\n * @param[in] isDecrypt Whether to decrypt the downloaded data\n * @param[in] callback The callback on progress or when complete\n * @return A Downloader.\n */\npublic 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\n\n/**\n * @brief Upload a file\n *\n * @param[in] rs Whether to use Reed-Solomon to generate parity shards\n * @param[in] fileOrData The file path or the text\n * @param[in] isFilePath Whether fileOrData is file path or text\n * @param[in] fileName The file name\n * @param[in] bucketId The bucket id\n * @param[in] ei The encryption info for file encryption and decryption(can be generated by function generateEncryptionInfo)\n * @param[in] callback The callback on progress or when complete\n * @return A Uploader.\n */\npublic Uploader storeFile(final boolean rs, final String filePath, final String fileName, final String bucketId, EncryptionInfo ei, final StoreFileCallback callback) throws GenaroException\n\n/**\n * @brief Decrypt a file\n *\n * @param[in] filePath The undecrypted file path\n * @param[in] key The key of AES\n * @param[in] iv The ctr of AES\n * @return The decrypted text.\n */\npublic static String decryptFileToText(String filePath, byte[] key, byte[] iv) throws GenaroException\n\n/**\n * @brief Encrypt the meta use AES-256-GCM combined with HMAC-SHA512 to filePath\n *\n * @param[in] meta The meta to be decrypted\n * @param[in] filePath The file path\n */\npublic void encryptMetaToFile(String meta, String filePath) throws GenaroException\n\n/**\n * @brief Decrypt the meta in filePath use AES-256-GCM combined with HMAC-SHA512\n *\n * @param[in] filePath The file path\n * @return The decrypted meta.\n */\npublic String decryptMetaFromFile(String filePath) throws GenaroException\n```\n\n## Example Usage\n\nInitialize:\n\n```java\nString bridgeUrl = \"http://47.100.33.60:8080\";\nString V3JSON = \"{ \\\"address\\\": \\\"aaad65391d2d2eafda9b2732000001d52a6a3dc8\\\",\n        \\\"crypto\\\": { \\\"cipher\\\": \\\"aes-128-ctr\\\",\n        \\\"ciphertext\\\": \\\"e968751f3d60827b6e6000006c024ecc82f33a6c55428be33249c83edba444ca\\\",\n        \\\"cipherparams\\\": { \\\"iv\\\": \\\"e80d9ec9b00000a143c756ec78066ad9\\\" }, \\\"kdf\\\": \\\"scrypt\\\",\n        \\\"kdfparams\\\": { \\\"dklen\\\": 32, \\\"n\\\": 262144, \\\"p\\\": 1, \\\"r\\\": 8, \\\"salt\\\":\n        \\\"ea7cb2b004db67d000003790caced7a96b636762f280b243e794fb5bef8ef74b\\\" },\n        \\\"mac\\\": \\\"ceb3789e77be8f2a7ab4d000001b54e048ad3f5b080b96e07759de7442e050d2\\\" },\n        \\\"id\\\": \\\"e28f31b4-1f43-428b-9b12-ab58000004b1\\\", \\\"version\\\": 3 }\";\nString passwd = \"xxxxxx\";\nGenaro api;\ntry {\n    api = new Genaro(bridgeUrl, V3JSON, passwd);\n} catch (Exception e) {\n    return;\n}\n```\n\nList buckets:\n\n```java\nCompletableFuture\u003cVoid\u003e fu = api.getBuckets(new GetBucketsCallback() {\n    @Override\n    public void onFinish(Bucket[] buckets) { }\n    @Override\n    public void onFail(String error) { }\n});\n\n// getBuckets is Non-Blocking, if you want to wait until it is finished, call fu.join()\n```\n\nDelete bucket:\n\n```java\nString bucketId = \"5bfcf77cea9b6322c5abd929\";\nCompletableFuture\u003cVoid\u003e fu = api.deleteBucket(bucketId, new DeleteBucketCallback() {\n    @Override\n    public void onFinish() { }\n    @Override\n    public void onFail(String error) { }\n}));\n\n// deleteBucket is Non-Blocking, if you want to wait until it is finished, call fu.join()\n```\n\nRename bucket:\n\n```java\nString bucketId = \"5bfcf77cea9b6322c5abd929\";\nString newName = \"abc\";\nCompletableFuture\u003cVoid\u003e fu = api.renameBucket(bucketId, newName, new RenameBucketCallback() {\n    @Override\n    public void onFinish() { }\n    @Override\n    public void onFail(String error) { }\n}\n\n// renameBucket is Non-Blocking, if you want to wait until it is finished, call fu.join()\n```\n\nList files:\n\n```java\nString bucketId = \"5bfcf77cea9b6322c5abd929\";\nCompletableFuture\u003cVoid\u003e fu = api.listFiles(bucketId, new ListFilesCallback() {\n    @Override\n    public void onFinish(GenaroFile[] files) { }\n    @Override\n    public void onFail(String error) { }\n}\n\n// listFiles is Non-Blocking, if you want to wait until it is finished, call fu.join()\n```\n\nDelete file:\n\n```java\nString bucketId = \"5bfcf77cea9b6322c5abd929\";\nString fileId = \"5c0e1289bbdd6f2d157dd8b2\";\nCompletableFuture\u003cVoid\u003e fu = api.deleteFile(bucketId, fileId, new DeleteFileCallback() {\n    @Override\n    public void onFinish() { }\n    @Override\n    public void onFail(String error) { }\n}\n\n// deleteFile is Non-Blocking, if you want to wait until it is finished, call fu.join()\n```\n\nUpload file:\n\n```java\nString bucketId = \"5bfcf4ea7991d267f4eb53b4\";\nString fileOrData = \"xxxxxx\";\nboolean isFilePath = true;\nString fileName = \"abc.txt\";\nboolean rs = true;\n\nEncryptionInfo ei = genaro.generateEncryptionInfo(null, bucketId);\nUploader uploader = null;\ntry {\n    uploader = api.storeFile(rs, fileOrData, isFilePath, fileName, bucketId, ei, new StoreFileCallback() {\n        @Override\n        public void onBegin(long fileSize) { }\n        @Override\n        public void onProgress(float progress) { }\n        @Override\n        public void onCancel() { }\n        @Override\n        public void onFail(String error) { }\n        @Override\n        public void onFinish(String fileId, byte[] sha256OfEncrypted) { }\n    });\n} catch (GenaroException e) { }\n\n// storeFile is Non-Blocking, if you want to wait until it is finished, call uploader.join()\n// if you want to cancel it, call uploader.cancel()\n```\n\nDownload file:\n\n```java\nString bucketId = \"5bfcf4ea7991d267f4eb53b4\";\nString fileId = \"5c0103fd5a158a5612e67461\";\nString filePath = \"xxxxxx\";\n\nDownloader downloader = null;\ntry {\n    downloader = genaro.resolveFile(bucketId, fileId, path, true, true, null, null, new ResolveFileCallback() {\n        @Override\n        public void onBegin() { }\n        @Override\n        public void onProgress(float progress) { }\n        @Override\n        public void onCancel() { }\n        @Override\n        public void onFail(String error) { }\n        @Override\n        public void onFinish(long fileBytes, byte[] sha256) { }\n    });\n} catch (GenaroException e) { }\n\n// resolveFile is Non-Blocking, if you want to wait until it is finished, call downloader.join()\n// if you want to cancel it, call downloader.cancel()\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgenaronetwork%2Flibgenaro-android","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgenaronetwork%2Flibgenaro-android","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgenaronetwork%2Flibgenaro-android/lists"}