newt

package module
v0.0.0-...-96c81bc Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 26, 2016 License: GPL-3.0 Imports: 11 Imported by: 0

README

Ninja Encrypted Web Token (NEWT)

A proprietary token flavor of JWT, based off of https://github.com/dgrijalva/jwt-go

Information

What is a NEWT?

It's a signed JSON object that does something useful. In particular, it's designed to be used as an authentication token. A token is made of three parts, separated by .s. The first two parts are JSON objects that have been base64url encoded. The last part is the signature.

The first part is called the header. It contains the necesssary information for verifying the last part, the signature. In this case, NEWTs only support one method of encryption: AES-128 (Rijndael), but this could be expanded in the future.

The part in the middle is the interesting segment. It's called the Claims and contains the actual stuff you care about. Refer to the RFC for information about reserved keys and the proper way to add your own.

What's in the box?

This library supports the parsing and verification as well as the generation and signing of NEWTs. Current supported signing algorithm(s) are AES-128, though hooks are present for adding your own.

NEWT vs JWT

Why not just use a JWT, then? Well, firstly, the NEWT was designed to be a proprietary format. And the major difference is that while JWT supports many types of signing methods, it does not (yet) support AES; the NEWT does.

Format

Header
{
    "alg": "AES128",
    "typ": "NEWT"
}
Payload
{
    "foo": "bar"
}
Example NEWT
eyJhbGciOiJBRVMxMjgiLCJ0eXAiOiJORVdUIn0.eyJmb28iOiJiYXIifQ.l�����)�¶R��M�bH▲�L�H�h"����Qu���"�7���§�☻`P�OH���2▲�10-�
  • The header and payload are each encrypted using the AES-128 (Rijndael) standard.
  • A third segment contains signature verification information, and is also encrypted with AES-128.
  • The header and payload are Base64-encoded. This allows each segment to be placed in a single string with delimiters.
  • These three segments are separated by a . delimiter.

Usage

Import

import gitlab.trad.tradestation.com/bshef/newt

Create a Token
// Structure to hold key information for AES-128 encryption.
var key = map[string]string {
    "key": string(aesKey),
    "iv": string(aesKey),
}

// Claims payload.
var claims = map[string]interface{}{"foo": "bar"}

// Create token.
token := newt.New(newt.SigningMethodAES128)
token.Claims = claims  
encryptedTokenString, _ := token.SignedString(key)
Parse a Request
// Create request.
r, _ := http.NewRequest("GET", "/", nil)
r.Header.Set("Authorization", fmt.Sprintf("Bearer %v", encryptedTokenString))

// A newt.KeyFunc can be used to validate the signing method.
// In this case, the function does nothing and won't report errors.
// A newt.KeyFunc MUST be supplied, even if it does nothing.
var keyFunc newt.KeyFunc = func(t *newt.Token) (interface{}, error) { return nil, nil }

// Parse the token from the request.
parsedToken, err := newt.ParseFromRequest(req, keyFunc)

// Validate success of token parsing.
success := (err == nil && parsedToken.Valid)

Test

go test -v

Output:

=== RUN   TestParser_Parse
--- PASS: TestParser_Parse (0.00s)
        parser_test.go:94:
                TEST DATA: simple
�OH���2▲�10-�r_test.go:100: [simple]    data.tokenString: eyJhbGciOiJBRVMxMjgiLCJ0eXAiOiJORVdUIn0.eyJmb28iOiJiYXIifQ.l�����)�¶R��M�bH▲�L�H�h"����Qu���"�7���§�☻`P
�OH���2▲�10-� Valid:true}82044dc0 Header:map[alg:AES128 typ:NEWT] Claims:map[foo:bar] Signature:l�����)�¶R��M�bH▲�L�H�h"����Qu���"�7���§�☻`P�h"����Qu���"�7���§�☻`P
        parser_test.go:94:
                TEST DATA: emptyKeyFunc
�OH���2▲�10-�r_test.go:100: [emptyKeyFunc]      data.tokenString: eyJhbGciOiJBRVMxMjgiLCJ0eXAiOiJORVdUIn0.eyJmb28iOiJiYXIifQ.l�����)�¶R��M�bH▲�L�H�h"����Qu���"�7���§�☻`P
�OH���2▲�10-� Valid:true}82044dc0 Header:map[alg:AES128 typ:NEWT] Claims:map[foo:bar] Signature:l�����)�¶R��M�bH▲�L�H�h"����Qu���"�7���§�☻`P�bH▲�L�H�h"����Qu���"�7���§�☻`P
        parser_test.go:94:
                TEST DATA: nilKeyFunc
�OH���2▲�10-�r_test.go:100: [nilKeyFunc]        data.tokenString: eyJhbGciOiJBRVMxMjgiLCJ0eXAiOiJORVdUIn0.eyJmb28iOiJiYXIifQ.l�����)�¶R��M�bH▲�L�H�h"����Qu���"�7���§�☻`P
�OH���2▲�10-� Method:0xc082044dc0 Header:map[alg:AES128 typ:NEWT] Claims:map[foo:bar] Signature: Valid:false}yJmb28iOiJiYXIifQ.l�����)�¶R��M�bH▲�L�H�h"����Qu���"�7���§�☻`P
=== RUN   TestParseRequest
--- PASS: TestParseRequest (0.00s)
        parser_test.go:133:
                TEST DATA: simple
�OH���2▲�10-�r_test.go:139: [simple]    data.tokenString: eyJhbGciOiJBRVMxMjgiLCJ0eXAiOiJORVdUIn0.eyJmb28iOiJiYXIifQ.l�����)�¶R��M�bH▲�L�H�h"����Qu���"�7���§�☻`P
        parser_test.go:145: [simple]    Request: &{Method:GET URL:/ Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Authorization:[Bearer eyJhbGciOiJBRVMxMjgiLCJ0eXAiOiJORVdUIn0.eyJmb28iOiJiYXIifQ.l�����)�¶R��M�bH▲�L�H�h"����Qu���"�7����OH���2▲�10-�]] Body:<nil> ContentLength:0 TransferEncoding:[] Close:false Host: Form:map[] PostForm:map[] MultipartForm:<nil> Trailer:map[] RemoteAddr: RequestURI: TLS:<nil> Cancel:<nil>}
�OH���2▲�10-� Valid:true}82044dc0 Header:map[alg:AES128 typ:NEWT] Claims:map[foo:bar] Signature:l�����)�¶R��M�bH▲�L�H�h"����Qu���"�7���§�☻`P�h"����Qu���"�7���§�☻`P
        parser_test.go:133:
                TEST DATA: emptyKeyFunc
�OH���2▲�10-�r_test.go:139: [emptyKeyFunc]      data.tokenString: eyJhbGciOiJBRVMxMjgiLCJ0eXAiOiJORVdUIn0.eyJmb28iOiJiYXIifQ.l�����)�¶R��M�bH▲�L�H�h"����Qu���"�7���§�☻`P
        parser_test.go:145: [emptyKeyFunc]      Request: &{Method:GET URL:/ Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Authorization:[Bearer eyJhbGciOiJBRVMxMjgiLCJ0eXAiOiJORVdUIn0.eyJmb28iOiJiYXIifQ.l�����)�¶R��M�bH▲�L�H�h"����Qu��OH���2▲�10-�]] Body:<nil> ContentLength:0 TransferEncoding:[] Close:false Host: Form:map[] PostForm:map[] MultipartForm:<nil> Trailer:map[] RemoteAddr: RequestURI: TLS:<nil> Cancel:<nil>}
�OH���2▲�10-� Valid:true}82044dc0 Header:map[alg:AES128 typ:NEWT] Claims:map[foo:bar] Signature:l�����)�¶R��M�bH▲�L�H�h"����Qu���"�7���§�☻`P�bH▲�L�H�h"����Qu���"�7���§�☻`P
        parser_test.go:133:
                TEST DATA: nilKeyFunc
�OH���2▲�10-�r_test.go:139: [nilKeyFunc]        data.tokenString: eyJhbGciOiJBRVMxMjgiLCJ0eXAiOiJORVdUIn0.eyJmb28iOiJiYXIifQ.l�����)�¶R��M�bH▲�L�H�h"����Qu���"�7���§�☻`P
        parser_test.go:145: [nilKeyFunc]        Request: &{Method:GET URL:/ Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[Authorization:[Bearer eyJhbGciOiJBRVMxMjgiLCJ0eXAiOiJORVdUIn0.eyJmb28iOiJiYXIifQ.l�����)�¶R��M�bH▲�L�H�h"����Qu��OH���2▲�10-�]] Body:<nil> ContentLength:0 TransferEncoding:[] Close:false Host: Form:map[] PostForm:map[] MultipartForm:<nil> Trailer:map[] RemoteAddr: RequestURI: TLS:<nil> Cancel:<nil>}
�OH���2▲�10-� Method:0xc082044dc0 Header:map[alg:AES128 typ:NEWT] Claims:map[foo:bar] Signature: Valid:false}yJmb28iOiJiYXIifQ.l�����)�¶R��M�bH▲�L�H�h"����Qu���"�7���§�☻`P
PASS
ok      gitlab.com/bshef/newt   0.052s

Note that the output can be a little confused due to invalid escape characters generated as a result of AES-128 encryption. It may be prudent to add another layer of Base-64 encoding on top of the AES-128 encrypted string to make it more output-friendly.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var TimeFunc = time.Now

TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time).

Functions

func DecodeSegment

func DecodeSegment(seg string) ([]byte, error)

DecodeSegment decodes specific base64url encoding with padding stripped

func EncodeSegment

func EncodeSegment(seg []byte) string

EncodeSegment encodes specific base64url encoding with padding stripped

func RegisterSigningMethod

func RegisterSigningMethod(alg string, f func() SigningMethod)

RegisterSigningMethod registers the "alg" name and a factory function for signing method. This is typically done during init() in the method's implementation

Types

type KeyFunc

type KeyFunc func(*Token) (interface{}, error)

KeyFunc defines the type of function which receives a parsed token and then returns it for validating.

type Parser

type Parser struct {
	ValidMethods  []string // If populated, only these methods will be considered valid
	UseJSONNumber bool     // Use JSON Number format in JSON decoder
}

Parser defines configuration values for the Parser instance.

func (*Parser) Parse

func (p *Parser) Parse(tokenString string, keyFunc KeyFunc) (*Token, error)

Parse parses, validates, and returns a token (or error, if one arises). keyFunc will receive the parsed token and should return the key for validating.

type SigningMethod

type SigningMethod interface {
	Verify(signingString, signature string, key interface{}) error // Returns nil if signature is valid
	Sign(signingString string, key interface{}) (string, error)    // Returns encoded signature or error
	Alg() string                                                   // Returns the alg identifier for this method (example: 'AES128')
}

SigningMethod defines the type of signing used on the token. Implement SigningMethod to add new methods for signing or verifying tokens.

func GetSigningMethod

func GetSigningMethod(alg string) (method SigningMethod)

GetSigningMethod gets a signing method from an "alg" string

type SigningMethodAES

type SigningMethodAES struct {
	Name string
}

SigningMethodAES implements the AES family of signing methods

var (
	SigningMethodAES128 *SigningMethodAES
)

Specific instances for AES-128 (Rijndael) and any additional AES flavors.

func (*SigningMethodAES) Alg

func (m *SigningMethodAES) Alg() string

Alg returns the signing method name

func (*SigningMethodAES) Decrypt

func (m *SigningMethodAES) Decrypt(encryptedString string, key string, iv string) (string, error)

Decrypt performs AES-128 (Rijndael) decryption on an encrypted string using a provided key and iv.

func (*SigningMethodAES) Encrypt

func (m *SigningMethodAES) Encrypt(rawString string, key string, iv string) (string, error)

Encrypt performs AES-128 (Rijndael) decryption on a raw, unencrypted string using a provided key and iv.

func (*SigningMethodAES) Sign

func (m *SigningMethodAES) Sign(signingString string, key interface{}) (string, error)

Sign implements the Encrypt function for this signing method. key must be a map[string]string with indexes "key" and "iv".

func (*SigningMethodAES) Verify

func (m *SigningMethodAES) Verify(signingString, signature string, key interface{}) error

Verify in this case returns nil, because there is no defined way to verify an AES signing method. This is presently included to avoid breaking patterns established by other SigningMethods defined elsewhere. TODO - Define this

type Token

type Token struct {
	Raw       string                 // The raw token. Populated when you Parse a token
	Method    SigningMethod          // The signing method used or to be used
	Header    map[string]interface{} // The first segment of the token
	Claims    map[string]interface{} // The second segment of the token
	Signature string                 // The third segment of the token. Populated when you Parse a token
	Valid     bool                   // Is the token valid? Populated when you Parse/Verify a token
}

Token defines the data structure representing a Ninja Encrypted Token.

func New

func New(method SigningMethod) *Token

New creates a new Token. Takes a signing method

func Parse

func Parse(tokenString string, keyFunc KeyFunc) (*Token, error)

Parse parses, validates, and returns a token. keyFunc will receive the parsed token and should return the key for validating.

func ParseFromRequest

func ParseFromRequest(req *http.Request, keyFunc KeyFunc) (token *Token, err error)

ParseFromRequest will try to find the token in an http.Request. This method will call ParseMultipartForm if there's no token in the header. Currently, it looks in the Authorization header as well as looking for an 'access_token' request parameter in req.Form.

func (*Token) SignedString

func (t *Token) SignedString(key interface{}) (string, error)

SignedString returns the complete, signed token

func (*Token) SigningString

func (t *Token) SigningString() (string, error)

SigningString generates the signing string.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL