{"id":22783511,"url":"https://github.com/tap30/hiss","last_synced_at":"2025-04-15T18:26:48.225Z","repository":{"id":228874340,"uuid":"774114212","full_name":"Tap30/hiss","owner":"Tap30","description":"A simple Java/Kotlin field-level encryption library.","archived":false,"fork":false,"pushed_at":"2025-01-21T21:30:13.000Z","size":150,"stargazers_count":13,"open_issues_count":7,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-28T23:33:53.609Z","etag":null,"topics":["encryption","java","kotlin"],"latest_commit_sha":null,"homepage":"","language":"Java","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/Tap30.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":"2024-03-19T00:58:38.000Z","updated_at":"2025-03-27T18:07:39.000Z","dependencies_parsed_at":"2024-04-07T10:32:38.929Z","dependency_job_id":"bb26951a-6b09-4a8c-adc7-9d92dc6d4438","html_url":"https://github.com/Tap30/hiss","commit_stats":null,"previous_names":["tap30/hiss"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tap30%2Fhiss","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tap30%2Fhiss/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tap30%2Fhiss/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tap30%2Fhiss/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Tap30","download_url":"https://codeload.github.com/Tap30/hiss/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249127968,"owners_count":21217055,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["encryption","java","kotlin"],"created_at":"2024-12-11T22:08:20.348Z","updated_at":"2025-04-15T18:26:48.218Z","avatar_url":"https://github.com/Tap30.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hiss\n\nHiss is a Java/Kotlin field-level encryption and hashing library\nwhich lets you encrypt and calculate hash of only selected (annotated) fields of an object.\n\nIt is most useful when you want to persist or send an object which has sensitive fields.\n\nThe motivation behind this project was we wanted to\nencrypt [personally identifiable information (PII)](https://en.wikipedia.org/wiki/Personal_data)\nof our users prior to persisting them in the database that in case of\na data breach or unauthorized access, user identities would be protected.\n\n## Contents\n\n* [Quick Start](#quick-start)\n    * [Adding Hiss Dependency](#adding-hiss-dependency)\n    * [Creating Hiss Instance](#creating-hiss-instance)\n    * [Annotating Fields](#annotating-fields)\n    * [Encrypting Object](#encrypting-object)\n* [How does Hiss work?](#how-does-hiss-work)\n    * [Overview](#overview)\n    * [Use of Getters and Setters](#use-of-getters-and-setters)\n    * [Nested Classes and Usage of `@EncryptedInside`](#nested-classes-and-usage-of-encryptedinside)\n    * [Hash Calculation](#hash-calculation)\n    * [Partial Encryption](#partial-encryption)\n    * [Supported Algorithms](#supported-algorithms)\n* [Hiss Instantiation](#hiss-instantiation)\n    * [Hiss Properties](#hiss-properties)\n        * [Creating Properties From Environment Variables](#creating-properties-from-environment-variables)\n    * [Key Integrity Validation](#key-integrity-validation)\n\n## Quick Start\n\nUsing Hiss is straight forward; by adding Hiss dependency and annotating your classes you're good to go.\n\n**Hiss is also integrated with Spring Data\nMongo. [Check this out to find out more](https://github.com/Tap30/hiss-spring-boot-mongo-starter).**\n\n### Adding Hiss Dependency\n\nApache Maven:\n\n```xml\n\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.tap30\u003c/groupId\u003e\n    \u003cartifactId\u003ehiss\u003c/artifactId\u003e\n    \u003cversion\u003e0.12.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nGradle (Groovy):\n\n```groovy\nimplementation 'io.github.tap30:hiss:0.12.0'\n```\n\nGradle (Kotlin):\n\n```kotlin\nimplementation(\"io.github.tap30:hiss:0.12.0\")\n```\n\n### Creating Hiss Instance\n\nTo create an Hiss instance, keys and default encryption and hashing algorithms must be configured;\nbelow is simple configuration by which an Hiss instance can be created. For more details [see here](#hiss-instantiation).\n\n```java\nvar properties = HissProperties.builder()\n        .keys(Set.of(Key.builder()\n                .id(\"default_key\")\n                .key(Base64.getDecoder().decode(\"AAAAAAAAAAAAAAAAAAAAAA==\")) // \n                .keyHash(\"$2a$12$3T0VMnGMgvesehYomommnO02dbFOJuM/3elsmgmsB2/qlGSF3BIbe\")\n                .build()))\n        .defaultEncryptionKeyId(\"default_key\")\n        .defaultEncryptionAlgorithm(\"AES/GCM/NoPadding\")\n        .defaultHashingKeyId(\"default_key\")\n        .defaultHashingAlgorithm(\"HmacSHA256\")\n        .keyHashGenerationEnabled(false)\n        .build();\n\nvar hiss = HissFactory.createHiss(properties);\n```\n\n### Annotating Fields\n\nAssume we have a `User` class containing a phone number and a list of `Address`es;\nthe `Address` class contains postal code alongside other fields.\n\nWe want to make sure phone number is encrypted and its hash is calculated by which\nwe can search for a user by his/her phone number.\nWe also want to encrypt his/her postal code but the postal code is not searchable\n(at least in our imaginary app 😌).\n\nHere will be the code in Java:\n\n```java\nimport io.github.tap30.hiss.Encrypted;\nimport io.github.tap30.hiss.EncryptedInside;\n\npublic class User {\n    private String name;\n    @Encrypted\n    private String phoneNumber;\n    private String hashedPhoneNumber; // Hiss will automatically fill this field.\n    @EncryptedInside\n    private List\u003cAddress\u003e addresses;\n\n    // Getters and setters; Hiss will use these!\n}\n\npublic class Address {\n    private String name;\n    private String street;\n    private String city;\n    private String state;\n    @Encrypted(hashingEnabled = false)\n    private String postalCode;\n\n    // Getters and setters; Hiss will use these!\n}\n```\n\nAnd in Kotlin (`@Encrypted` can be only applied on `var` fields):\n\n```kotlin\nimport io.github.tap30.hiss.Encrypted\nimport io.github.tap30.hiss.EncryptedInside\n\ndata class User(\n    val name: String,\n    @Encrypted\n    var phoneNumber: String,\n    var hashedPhoneNumber: String,\n    @EncryptedInside\n    val addresses: List\u003cAddress\u003e\n)\n\ndata class Address(\n    val name: String,\n    val street: String,\n    val city: String,\n    val state: String,\n    @Encrypted(hashingEnabled = false)\n    val postalCode: String\n)\n```\n\n### Encrypting Object\n\nBy simply calling `hiss.encryptObject(user)`, the annotated fields will be encrypted\nand their hash string (if enabled) will be calculated.\n\nAlso, by calling `hiss.decryptObject(user)`, the annotated fields will be decrypted.\n\nAll methods in Hiss class are idempotent; meaning calling `encryptObject` twice,\nwon't result in encrypting fields twice and as for decryption, plain texts will be left untouched.\n\nThere is a [sample application in tests](src/test/java/io/github/tap30/hissapp/Application.java)\nwhich demonstrates more use cases of Hiss.\n\n## How does Hiss work?\n\n### Overview\n\nWhen you call `encryptObject` of Hiss, it'll scan all fields of the object using Java reflection.\nString fields annotated with `@Encrypted`, will be read using getters of the fields,\nand their value will be encrypted and their hash will be calculated, and the encrypted content and hash value\nwill be set using the fields setters.\n\nThe story is same for `decryptObject` while it only decrypts those fields.\n\nThe object field scanning will be done once per class and the scan result will be cached.\n\n### Use of Getters and Setters\n\nAs stated earlier, Hiss won't change value of fields directly. It relies on getters and setters\nof the fields. Thus, it is necessary to implement those in Java classes.\n\n#### Kotlin Data Classes\n\nFor Kotlin data classes, no getters or setters are needed for `var` fields\nas they are automatically generated in their Java representation.\n\nAs `val` fields are immutable, `@Encrypted` can't be used on them.\n\n### Nested Classes and Usage of `@EncryptedInside`\n\nRecall the `addresses` field of the `User` class in [Quick Start: Annotating Fields](#annotating-fields),\nwe've annotated the `addresses` field with `@EncryptedInside` to tell Hiss to scan fields inside them.\n\n`@EncryptedInside` can be used on non-primitive fields,\nsubtypes of `Iterable\u003cT\u003e` (e.g. `Set\u003cT\u003e`, `List\u003cT\u003e`, ...) and, subtypes of `Map\u003c?, T\u003e`.\n\nHere is an example of valid `@EncryptedInside` usages:\n\n```java\npublic class ValidEncryptedInsideUsage {\n    @EncryptedInside\n    private Address address;\n    \n    @EncryptedInside\n    private List\u003cAddress\u003e addressList;\n    \n    @EncryptedInside\n    private Map\u003cString, Address\u003e addressMap;\n    \n    // getters ...\n}\n```\n\n### Hash Calculation\n\nHash values of fields are most useful when you want to search on these fields.\n\nUnless you disable hash calculation of a field (i.e `@Encrypted(hashingEnabled = false)`),\nduring encryption, the hash value of the field will also be calculated.\n\nThe hash value will be stored in a different field having the pattern `hashed\u003cFIELD NAME\u003e`;\nfor example the field for storing hash value of field `phoneNumber`, will be `hashedPhoneNumber`.\nYou can provide your custom hash field name in `@Encrypted` annotation field `hashFieldName`.\nHere's an example in which we want to store hash value of `phoneNumber` in `searchablePhoneNumber`:\n\n```java\npublic class User {\n    @Encrypted(hashFieldName=\"searchablePhoneNumber\")  \n    private String phoneNumber;\n    private String searchablePhoneNumber; // The hash value will be stored here.\n  \n    // getters and setters ...\n}\n```\n\n### Partial Encryption\n\nBy setting `pattern` in `@Encrypted`, only parts matched with the pattern will be encrypted and hashed.\n\nFor example, having:\n\n```java\npublic class Message {\n\n  @Encrypted(pattern = \"\\\\d+\")\n  private String content;\n  private String hashedContent;\n\n  // getters and setters ...\n}\n\nvar message = new Message();\nmessage.setContent(\"User 123 called you.\");\n\nhiss.encryptObject(message);\n\nSystem.out.println(message.getContent());\nSystem.out.println(message.getHashedContent());\n```\n\nwill result in:\n\n```\nUser #$$#{aes/gcm/nopadding:default_key}{anibgQ6BsnMbFz5+mtNENjE1ioAaOm5J7T4pyEIhEKTiqeY=}#$$# called you.\nUser #$$#{hmacsha256:default_key}{wMwN/frvI3Dk1WcRF1/jSd727Uy6JdPHoB/G72VoIg0=}#$$# called you.\n```\n\n### Supported Algorithms\n\nFor encryption, these algorithms are supported:\n\n- [AES/CBC/PKCS5Padding](src/main/java/io/github/tap30/hiss/encryptor/impl/AesCbcPkcs5PaddingEncryptor.java)\n- [AES/GCM/NoPadding](src/main/java/io/github/tap30/hiss/encryptor/impl/AesGcmNoPaddingEncryptor.java)\n\nFor hashing, only [HmacSHA256](src/main/java/io/github/tap30/hiss/hasher/impl/HmacSha256Hasher.java) is supported.\n\nBy implementing [`Encryptor`](src/main/java/io/github/tap30/hiss/encryptor/Encryptor.java)\nand [`Hasher`](src/main/java/io/github/tap30/hiss/hasher/Hasher.java) interfaces, you can provide\nyour own algorithms. We'll talk more about it in [Hiss Instantiation](#hiss-instantiation).\n\n## Hiss Instantiation\n\nHiss can be instantiated using [`HissFactory`](src/main/java/io/github/tap30/hiss/HissFactory.java)'s `createHiss` methods.\n\n`createHiss` method requires [`HissProperties`](src/main/java/io/github/tap30/hiss/properties/HissProperties.java) instances.\nIn the overloaded method, it accepts sets of `Encryptor`s and `Hasher`s by which you can provide your own custom\nalgorithm implementations. The default algorithms will be available.\n\n### Hiss Properties\n\n[`HissProperties`](src/main/java/io/github/tap30/hiss/properties/HissProperties.java)\ncan be created using its builder, using environment variables, or by implementing\n[`HissPropertiesProvider`](src/main/java/io/github/tap30/hiss/properties/HissPropertiesProvider.java)\nand passing it to `HissProperties.withProvider`.\n\nHere are the fields in `HissProperties`:\n\n```java\n/**\n * Pairs of key ID (name) to key.\n */\nMap\u003cString, Key\u003e keys;\n/**\n * The key ID of the key by which encryption will be done. It must exist in `keys` map.\n */\nString defaultEncryptionKeyId;\n/**\n * The algorithm name by which encryption will be done.\n * It must exist among default or custom encryption algorithms.\n */\nString defaultEncryptionAlgorithm;\n/**\n * The key ID of the key by which hashing will be done. It must exist in `keys` map.\n */\nString defaultHashingKeyId;\n/**\n * The algorithm name by which hashing will be done.\n * It must exist among default or custom hashing algorithms.\n */\nString defaultHashingAlgorithm;\n/**\n * Whether to generate keys' hashes on Hiss instantiation. \n */\nboolean keyHashGenerationEnabled;\n```\n\nCreating `HissProperties` using its builder is straight-forward and explained in [Quick Start](#create-hiss-instance).\nIn the following, we'll describe creating key from environment variables.\n\n#### Creating Properties From Environment Variables\n\nBy calling `fromEnv` function of `HissProperties`, `HissProperties` will be created.\n\nHere are the mapping of the properties fields to environment variables:\n\n- `keys`:\n    - `HISS_KEYS_{Key ID}`: the base64 encoded representation of the key.\n    - `HISS_KEYS_{Key ID}__HASH`: the hash of the key.\n- `defaultEncryptionKeyId`: `HISS_DEFAULT_ENCRYPTION_KEY_ID`\n- `defaultEncryptionAlgorithm`: `HISS_DEFAULT_ENCRYPTION_ALGORITHM`\n- `defaultHashingKeyId`: `HISS_DEFAULT_HASHING_KEY_ID`\n- `defaultHashingAlgorithm`: `HISS_DEFAULT_HASHING_ALGORITHM`\n- `keyHashGenerationEnabled`: `HISS_KEY_HASH_GENERATION_ENABLED`\n\nBelow is a full working set of envs having two keys IDed `default_key` and `old_key`:\n\n```bash\nHISS_KEYS_DEFAULT_KEY='AAAAAAAAAAAAAAAAAAAAAA=='\nHISS_KEYS_DEFAULT_KEY___HASH='$2a$12$3T0VMnGMgvesehYomommnO02dbFOJuM/3elsmgmsB2/qlGSF3BIbe'\n\nHISS_KEYS_OLD_KEY='AQIDBAUGBwgJCgsMDQ4PEA=='\nHISS_KEYS_OLD_KEY___HASH='$2a$12$THkoYZHlqD/HvrSkKUDs9eyHwY7W2FmyJm6SMp4xeGfP2g7F6Ro/i'\n\nHISS_DEFAULT_ENCRYPTION_KEY_ID='default_key'\nHISS_DEFAULT_ENCRYPTION_ALGORITHM='aes-128-gcm'\n\nHISS_DEFAULT_HASHING_KEY_ID='default_key'\nHISS_DEFAULT_HASHING_ALGORITHM='hmac-sha256'\n\nHISS_KEY_HASH_GENERATION_ENABLED='true'\n```\n\n### Key Integrity Validation\n\nAbove we've seen \"key hash\". By setting `keyHashGenerationEnabled` to `true`, Hiss, upon instantiation, will\nprint hashes of the keys on the console.\n\nLater by providing these hashes, Hiss will make sure integrity of keys will be left untouched;\nthis should hopefully prevent accidental key change or manipulation 🤞.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftap30%2Fhiss","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftap30%2Fhiss","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftap30%2Fhiss/lists"}