https://github.com/ammario/isokey
Self-contained API keys via cryptographic signatures
https://github.com/ammario/isokey
security symmetric-keys
Last synced: 11 months ago
JSON representation
Self-contained API keys via cryptographic signatures
- Host: GitHub
- URL: https://github.com/ammario/isokey
- Owner: ammario
- License: mit
- Created: 2016-06-18T05:03:44.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2017-08-25T14:32:09.000Z (over 8 years ago)
- Last Synced: 2025-02-27T18:27:13.933Z (12 months ago)
- Topics: security, symmetric-keys
- Language: Go
- Homepage: https://godoc.org/gopkg.in/ammario/isokey.v2
- Size: 36.1 KB
- Stars: 121
- Watchers: 3
- Forks: 5
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Isokey
Isokey allows you to make and verify self-contained API keys without a database via HMAC/ECDSA signatures.
## Features
- Important information such as userID, key expire time, and flags are authenticated and stored within
the key.
- Use mutliple secrets
- Invalidate secrets and compromised keys
## Table Of Contents
- [Symmetric Keys](#symmetric-keys)
- [Make a key service](#make-a-key-service)
- [Sign a new key](#sign-a-new-key)
- [Verify key](#verify-key)
- [Using multiple secrets](#using-multiple-secrets)
- [Digest Structure](#digest-structure)
- [Asymmetric Keys](#asymmetric-keys)
- [Make a key pair](#make-a-key-pair)
- [Make key digest](#make-key-digest)
- [Verify key](#verify-key-1)
- [Digest Structure](#digest-structure-1)
- [Invalidating keys](#invalidating-keys)
# Symmetric Keys
## Make a key service
```go
ks := NewSymKeyService([]byte("super_secure111"))
```
## Sign a new key
```go
key := &Key{
UserID: 1,
Expires: time.Now().AddDate(0, 1, 0),
}
digest, err := ks.Sign(key)
if err != nil {
log.Fatalf("Failed to sign key: %v", err)
}
fmt.Printf("Digest is %v\n", digest)
```
## Verify key
```go
key, err = ks.Verify(digest)
if err != nil {
log.Fatalf("Failed to verify digest: %v", err)
}
// Key authenticated
fmt.Printf("Key: %+v\n", key)
```
## Using multiple secrets
The SecretVersion field is in included in the key object to enable
implementors to easily use multiple secrets.
A secret can be decided based on any feature of a key.
```go
ks.GetSecret = function(key *Key) (secret []byte){
if key.SecretVersion == 1 {
return []byte("sec1")
}
return nil
}
```
## Digest Structure
All binary values are big endian.
| Field | Type |
|--------|------|
| Signature | [16]byte |
| Made Time (Unix epoch timestamp) | uint32 |
| Expire Time (Unix epoch timestamp) | uint32 |
| Secret Version | uint32 |
| User ID | uint32 |
| Flags | uint32 |
Digests are encoded with Bitcoin's base58 alphabet.
It may seem intuitive to put the signature at the end of the digest. It's located
at the beginning as it makes eyeballing different keys easy.
# Asymmetric Keys
## Make a key pair
Make your private key
`openssl ecparam -genkey -name prime256v1 -outform DER -noout -out privatekey.der`
Make your public key
`openssl ec -in privatekey.der -inform DER -outform DER -pubout -out publickey.der`
## Make key digest
```go
privKey, _ = isokey.LoadPrivateKey("priv.key")
ks := NewAsymKeySigner(privKey)
key := &Key{
User: 1,
Expires: time.Now().Add(time.Hour)
}
digest, _ := ks.Sign(key)
fmt.Printf("Digest: %v", digest)
```
## Verify key
```go
pubKey, err := isokey.LoadPublicKey("pub.key")
if err != nil {
log.Fatalf("Failed to load pubkey: %v", err)
}
kv := NewAsymKeyVerifier(pubKey)
key, err := kv.Verify(digest)
if err != nil {
log.Fatalf("Failed to verify key: %v", err)
}
fmt.Printf("Key verified %+v\n", key)
```
## Digest Structure
All binary values are big endian.
| Field | Type |
|--------|------|
| R len | uint8
| R | []byte
| S Len | uint8
| S | []byte
| Made Time (Unix epoch timestamp) | uint32 |
| Expire Time (Unix epoch timestamp) | uint32 |
| Secret Version | uint32 |
| User ID | uint32 |
| Flags | uint32 |
Digests are encoded with Bitcoin's base58 alphabet.
# Invalidating keys
Expired keys always fail to validate.
You can add custom invalidation logic via the `Invalidator` field of verifiers.
```go
verifier.Invalidator = function(key *isokey.Key) bool {
// reject keys made before some time
if key.UserID == 10 && key.Made.Before(time.Date(2015, time.November, 10, 23, 0, 0, 0, time.UTC)) {
return true
}
return false
}
```