{"id":43733967,"url":"https://github.com/ncryptf/ncryptf-go","last_synced_at":"2026-02-05T10:35:41.706Z","repository":{"id":57691157,"uuid":"173186885","full_name":"ncryptf/ncryptf-go","owner":"ncryptf","description":"ncryptf for Go - Secure API authentication and end to end encryption ","archived":false,"fork":false,"pushed_at":"2020-05-02T22:56:57.000Z","size":57,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-06-20T11:14:15.853Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ncryptf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-02-28T21:02:10.000Z","updated_at":"2023-01-06T16:25:46.000Z","dependencies_parsed_at":"2022-08-27T19:41:06.816Z","dependency_job_id":null,"html_url":"https://github.com/ncryptf/ncryptf-go","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ncryptf/ncryptf-go","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncryptf%2Fncryptf-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncryptf%2Fncryptf-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncryptf%2Fncryptf-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncryptf%2Fncryptf-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ncryptf","download_url":"https://codeload.github.com/ncryptf/ncryptf-go/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncryptf%2Fncryptf-go/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29119232,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-05T09:40:36.738Z","status":"ssl_error","status_checked_at":"2026-02-05T09:36:49.977Z","response_time":65,"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":"2026-02-05T10:35:41.607Z","updated_at":"2026-02-05T10:35:41.695Z","avatar_url":"https://github.com/ncryptf.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ncryptf Go\n\n[![TravisCI](https://img.shields.io/travis/com/ncryptf/ncryptf-go.svg?style=flat-square \"TravisCI\")](https://travis-ci.com/ncryptf/ncryptf-go)\n[![Go Report Card](https://goreportcard.com/badge/github.com/ncryptf/ncryptf-go)](https://goreportcard.com/report/github.com/ncryptf/ncryptf-go)\n[![License](https://img.shields.io/badge/license-BSD-orange.svg?style=flat-square \"License\")](https://github.com/ncryptf/ncryptf-go/blob/master/LICENSE.md)\n\n\u003ccenter\u003e\n    \u003cimg src=\"https://github.com/ncryptf/ncryptf-go/blob/master/logo.png?raw=true\" alt=\"ncryptf logo\" width=\"400px\"/\u003e\n\u003c/center\u003e\n\nA library for facilitating hashed based KDF signature authentication, and end-to-end encrypted communication with compatible API's.\n\n## Installing\n\n1. Enable Go11 Modules by setting the `GO111MODULE` environment variable\n```\nGO111MODULE=on\n```\n2. Install normally\n```\ngo get github.com/ncryptf/ncryptf-go\n```\n\n## Testing\n\n```\ngo test ./...\n```\n\n## Documentation\n\n\n## HMAC+HKDF Authentication\n\nHMAC+HKDF Authentication is an Authentication method that allows ensures the request is not tampered with in transit. This provides resiliance not only against network layer manipulation, but also man-in-the-middle attacks.\n\nAt a high level, an HMAC signature is created based upon the raw request body, the HTTP method, the URI (with query parameters, if present), and the current date. In addition to ensuring the request cannot be manipulated in transit, it also ensures that the request is timeboxed, effectively preventing replay attacks.\n\nThe library itself is made available by importing the following struct:\n\nSupporting API's will return the following payload containing at minimum the following information.\n\n```json\n{\n    \"access_token\": \"7XF56VIP7ZQQOLGHM6MRIK56S2QS363ULNB5UKNFMJRQVYHQH7IA\",\n    \"refresh_token\": \"MA2JX5FXWS57DHW4OIHHQDCJVGS3ZKKFCL7XM4GNOB567I6ER4LQ\",\n    \"ikm\": \"bDEyECRvKKE8w81fX4hz/52cvHsFPMGeJ+a9fGaVvWM=\",\n    \"signing\": \"7v/CdiGoEI7bcj7R2EyDPH5nrCd2+7rHYNACB+Kf2FMx405und2KenGjNpCBPv0jOiptfHJHiY3lldAQTGCdqw==\",\n    \"expires_at\": 1472678411\n}\n```\n\nAfter extracting the elements, we can create signed request by doing the following:\n\n```go\nimport \"github.com/ncryptf/ncryptf-go\"\nimport \"encoding/base64\"\n\naccessToken := \"7XF56VIP7ZQQOLGHM6MRIK56S2QS363ULNB5UKNFMJRQVYHQH7IA\"\nrefreshToken := \"MA2JX5FXWS57DHW4OIHHQDCJVGS3ZKKFCL7XM4GNOB567I6ER4LQ\"\nikm := base64.StdEncoding.DecodeFromString(\"bDEyECRvKKE8w81fX4hz/52cvHsFPMGeJ+a9fGaVvWM=\")\nikm := base64.StdEncoding.DecodeFromString(\"7v/CdiGoEI7bcj7R2EyDPH5nrCd2+7rHYNACB+Kf2FMx405und2KenGjNpCBPv0jOiptfHJHiY3lldAQTGCdqw==\")\nexpiresAt := 1472678411\n\ntoken, err := NewToken(accessToken, refreshToken, ikm, signing, expiresAt)\nif err != nil {\n    auth, err := NewAuthorization(\"POST\", \"/api/v1/test\", token, time.Now(), \"{\\\"foo\\\":\\\"bar\\\"}\", nil, nil)\n\n    if err != nil {\n        header := auth.GetHeader()\n    }\n    // Handle authorization failure\n}\n\n// Handle token parsing failure\n```\n\n\u003e Note that the `date` property should be pre-offset when calling `Authorization` to prevent time skewing.\n\nThe `payload` parameter should be a JSON serializable string.\n\n### Version 2 HMAC Header\n\nThe Version 2 HMAC header, for API's that support it can be retrieved by calling:\n\n```go\nheader := auth.GetHeader()\n```\n\n### Version 1 HMAC Header\n\nFor API's using version 1 of the HMAC header, call `Authorization` with the optional `version` parameter set to `1` for the 6th parameter.\n\n```go\n auth, err := NewAuthorization(\"POST\", \"/api/v1/test\", token, time.Now(), \"{\\\"foo\\\":\\\"bar\\\"}\", 1, nil)\n\nif err != nil {\n    header := auth.GetHeader()\n}\n```\n\nThis string can be used in the `Authorization` Header\n\n#### Date Header\n\nThe Version 1 HMAC header requires an additional `X-Date` header. The `X-Date` header can be retrieved by calling `auth.GetDateString()`\n\n## Encrypted Requests \u0026 Responses\n\nThis library enables clients to establish and trusted encrypted session on top of a TLS layer, while simultaniously (and independently) providing the ability authenticate and identify a client via HMAC+HKDF style authentication.\n\nThe rationale for this functionality includes but is not limited to:\n\n1. Necessity for extra layer of security\n2. Lack of trust in the network or TLS itself (see https://blog.cloudflare.com/incident-report-on-memory-leak-caused-by-cloudflare-parser-bug/)\n3. Need to ensure confidentiality of the Initial Key Material (IKM) provided by the server for HMAC+HKDF authentication\n4. Need to ensure confidentiality of user submitted credentials to the API for authentication\n\nThe primary reason you may want to establish an encrypted session with the API itself is to ensure confidentiality of the IKM to prevent data leakages over untrusted networks to avoid information being exposed in a Cloudflare like incident (or any man-in-the-middle attack). Encrypted sessions enable you to utilize a service like Cloudflare should a memory leak occur again with confidence that the IKM and other secure data would not be exposed.\n\n#### Encryption Keys\n\nEncryption uses a sodium crypto box. A keypair can be generated as follows when using `lazy-sodium`.\n\n```go\nimport \"ncryptf\"\n\nfunc GetKeypair() *Keypair {\n    return ncryptf.GenerateKeypair()\n}\n```\n\n#### Signing Keys\n\nEncryption uses a sodium signature. A keypair for signing can be generated as follows using `lazy-sodium`:\n\n```go\nimport \"ncryptf\"\n\nfunc GenerateSigningKeypair() *Keypair {\n    return ncryptf.GenerateKeypair()\n}\n```\n\n### Encrypted Request Body\n\nPayloads can be encrypted as follows:\n\n```go\nimport \"github.com/ncryptf/ncryptf-go\"\nimport \"encoding/base64\"\n\npayload := \"{\\\"foo\\\":\\\"bar\\\"}\"\n\n// Generate your signing keypair or use your own\nkp := GenerateKeypair()\nsk := GenerateSigningKeypair()\n\n// Mock for a remote public key\nrk := GenerateKeypair()\n\nreq, err := NewRequest(kp.GetSecretKey(), sk.GetSecretKey())\nif err != nil {\n    // Error when generating the request struct\n}\n\ncipher, err := request.Encrypt(payload, rk.GetPublicKey())\nif err != nil {\n    // Error encrypting the message\n}\n\nmessage := base64.StdEncoding.EncodeToString(cipher)\n\n// Do your http request with message here\n```\n\n\n\u003e Note that you need to have a pre-bootstrapped public key to encrypt data. For the v1 API, this is typically this is returned by `/api/v1/server/otk`.\n\n### Decrypting Responses\n\nResponses from the server can be decrypted as follows:\n\n```go\nimport \"github.com/ncryptf/ncryptf-go\"\nimport \"encoding/base64\"\n\n// Assuming http.Client is doing your http request\nresp, err := client.Do(req)\n\ndefer resp.Body.Close()\n\nbodyBytes, err := ioutil.ReadAll(resp.Body)\nbodyString := string(bodyBytes)\nresponseBody, err := base64.StdEncoding.DecodeString(bodyString)\n\nresponse, err := NewResponse(kp.GetSecretKey())\nmessage, err := response.Decrypt(responseBody)\n\n// Message contains your decrypted string\n```\n\n### V2 Encrypted Payload\n\nVerison 2 works identical to the version 1 payload, with the exception that all components needed to decrypt the message are bundled within the payload itself, rather than broken out into separate headers. This alleviates developer concerns with needing to manage multiple headers.\n\nThe version 2 payload is described as follows. Each component is concatanated together.\n\n| Segment | Length |\n|---------|--------|\n| 4 byte header `DE259002` in binary format | 4 BYTES |\n| Nonce | 24 BYTES |\n| The public key associated to the private key | 32 BYTES |\n| Encrypted Body | X BYTES |\n| Signature Public Key | 32 BYTES |\n| Signature or raw request body | 64 BYTES |\n| Checksum of prior elements concatonated together | 64 BYTES |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fncryptf%2Fncryptf-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fncryptf%2Fncryptf-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fncryptf%2Fncryptf-go/lists"}