├── python3
├── src
│ └── org
│ │ ├── __init__.py
│ │ └── webpki
│ │ ├── __init__.py
│ │ └── json
│ │ ├── __init__.py
│ │ ├── LICENSE.PSF
│ │ └── NumberToJson.py
├── .gitignore
├── README.md
└── test
│ ├── verify-canonicalization.py
│ └── verify-numbers.py
├── java
├── .gitignore
├── miscellaneous
│ ├── webpki.properties
│ ├── README.md
│ ├── src
│ │ ├── Unicode2UTF16.java
│ │ ├── ES6InterActive.java
│ │ ├── AddEdgeCases.java
│ │ ├── F32InterActive.java
│ │ ├── CanonicalizerTest.java
│ │ ├── ES6NumberTest.java
│ │ ├── SortingSchemes.java
│ │ ├── org
│ │ │ └── webpki
│ │ │ │ └── util
│ │ │ │ └── DebugFormatter.java
│ │ └── BrowserCodeGenerator.java
│ └── build.xml
├── canonicalizer
│ ├── dist
│ │ └── json-canonicalizer.jar
│ ├── .classpath
│ ├── .project
│ ├── build.xml
│ ├── README.md
│ └── src
│ │ └── org
│ │ └── webpki
│ │ └── jcs
│ │ └── NumberToJSON.java
└── deprecated
│ └── org
│ └── webpki
│ └── jcs
│ ├── NumberToJSON.java
│ ├── NumberFastDtoaBuilder.java
│ ├── NumberDoubleHelper.java
│ ├── NumberDiyFp.java
│ └── NumberCachedPowers.java
├── testdata
├── output
│ ├── unicode.json
│ ├── arrays.json
│ ├── structures.json
│ ├── values.json
│ ├── french.json
│ └── weird.json
├── input
│ ├── unicode.json
│ ├── arrays.json
│ ├── french.json
│ ├── structures.json
│ ├── values.json
│ └── weird.json
├── outhex
│ ├── unicode.txt
│ ├── arrays.txt
│ ├── structures.txt
│ ├── values.txt
│ ├── french.txt
│ └── weird.txt
├── numgen.js
├── README.md
└── numgen.go
├── .gitattributes
├── dotnet
├── es6numbercli
│ ├── README.md
│ ├── es6numbercli.csproj
│ └── Program.cs
├── version.json
├── jsoncanonicalizer
│ ├── README.md
│ └── jsoncanonicalizer.csproj
├── es6numberserializer
│ ├── es6numberserializer.csproj
│ ├── README.md
│ ├── NumberToJson.cs
│ ├── NumberFastDToABuilder.cs
│ ├── NumberDoubleHelper.cs
│ ├── NumberDiyFp.cs
│ └── NumberCachedPowers.cs
├── .editorconfig
├── verify-numbers
│ ├── verify-numbers.csproj
│ └── Program.cs
├── verify-canonicalization
│ ├── verify-canonicalization.csproj
│ ├── ArrayUtil.cs
│ └── Program.cs
├── json.net.sign
│ ├── json.net.sign.csproj
│ ├── Int64Converter.cs
│ ├── UTCStrictDateConverter.cs
│ ├── Base64UrlConverter.cs
│ ├── README.md
│ ├── Program.cs
│ └── SignatureSupport.cs
├── README.md
├── dotnet.sln
└── .gitignore
├── .project
├── node-es6
├── README.md
├── verify-canonicalization.js
├── verify-numbers.js
└── canonicalize.js
├── JSON.canonify.md
├── LICENSE
├── go
├── README.md
├── src
│ └── webpki.org
│ │ └── jsoncanonicalizer
│ │ └── es6numfmt.go
└── test
│ ├── verify-canonicalization.go
│ └── verify-numbers.go
├── REST.signatures.md
└── README.md
/python3/src/org/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/java/.gitignore:
--------------------------------------------------------------------------------
1 | .tmp/
2 | bin/
3 |
4 |
--------------------------------------------------------------------------------
/python3/src/org/webpki/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/python3/src/org/webpki/json/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/python3/.gitignore:
--------------------------------------------------------------------------------
1 | **/__pycache__
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/testdata/output/unicode.json:
--------------------------------------------------------------------------------
1 | {"Unnormalized Unicode":"Å"}
--------------------------------------------------------------------------------
/testdata/output/arrays.json:
--------------------------------------------------------------------------------
1 | [56,{"1":[],"10":null,"d":true}]
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Disable LF normalization for all files
2 | * -text
--------------------------------------------------------------------------------
/testdata/input/unicode.json:
--------------------------------------------------------------------------------
1 | {
2 | "Unnormalized Unicode":"A\u030a"
3 | }
4 |
--------------------------------------------------------------------------------
/dotnet/es6numbercli/README.md:
--------------------------------------------------------------------------------
1 | ## Interactive ES6 Compatible JSON Number debugger for .NET
2 |
--------------------------------------------------------------------------------
/java/miscellaneous/webpki.properties:
--------------------------------------------------------------------------------
1 | es6test.file=c:/es6/numbers/es6testfile100m.txt
2 |
3 |
--------------------------------------------------------------------------------
/dotnet/version.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.0",
3 | "publicReleaseRefSpec": [
4 | "^refs/heads/rel$"
5 | ],
6 | }
--------------------------------------------------------------------------------
/testdata/input/arrays.json:
--------------------------------------------------------------------------------
1 | [
2 | 56,
3 | {
4 | "d": true,
5 | "10": null,
6 | "1": [ ]
7 | }
8 | ]
9 |
--------------------------------------------------------------------------------
/testdata/outhex/unicode.txt:
--------------------------------------------------------------------------------
1 | 7b 22 55 6e 6e 6f 72 6d 61 6c 69 7a 65 64 20 55 6e 69 63 6f 64 65 22 3a 22 41 cc 8a 22 7d
2 |
--------------------------------------------------------------------------------
/testdata/outhex/arrays.txt:
--------------------------------------------------------------------------------
1 | 5b 35 36 2c 7b 22 31 22 3a 5b 5d 2c 22 31 30 22 3a 6e 75 6c 6c 2c 22 64 22 3a 74 72 75 65 7d 5d
2 |
--------------------------------------------------------------------------------
/testdata/output/structures.json:
--------------------------------------------------------------------------------
1 | {"":"empty","1":{"\n":56,"f":{"F":5,"f":"hi"}},"10":{},"111":[{"E":"no","e":"yes"}],"A":{},"a":{}}
--------------------------------------------------------------------------------
/testdata/output/values.json:
--------------------------------------------------------------------------------
1 | {"literals":[null,true,false],"numbers":[333333333.3333333,1e+30,4.5,0.002,1e-27],"string":"€$\u000f\nA'B\"\\\\\"/"}
--------------------------------------------------------------------------------
/testdata/output/french.json:
--------------------------------------------------------------------------------
1 | {"peach":"This sorting order","péché":"is wrong according to French","pêche":"but canonicalization MUST","sin":"ignore locale"}
--------------------------------------------------------------------------------
/java/canonicalizer/dist/json-canonicalizer.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cyberphone/json-canonicalization/master/java/canonicalizer/dist/json-canonicalizer.jar
--------------------------------------------------------------------------------
/dotnet/jsoncanonicalizer/README.md:
--------------------------------------------------------------------------------
1 | ## JCS (RFC 8785) compatible canonicalizer for .NET
2 |
3 | The project **verify-canonicalization** contains the actual test program.
4 |
--------------------------------------------------------------------------------
/testdata/input/french.json:
--------------------------------------------------------------------------------
1 | {
2 | "peach": "This sorting order",
3 | "péché": "is wrong according to French",
4 | "pêche": "but canonicalization MUST",
5 | "sin": "ignore locale"
6 | }
7 |
--------------------------------------------------------------------------------
/testdata/input/structures.json:
--------------------------------------------------------------------------------
1 | {
2 | "1": {"f": {"f": "hi","F": 5} ,"\n": 56.0},
3 | "10": { },
4 | "": "empty",
5 | "a": { },
6 | "111": [ {"e": "yes","E": "no" } ],
7 | "A": { }
8 | }
--------------------------------------------------------------------------------
/testdata/input/values.json:
--------------------------------------------------------------------------------
1 | {
2 | "numbers": [333333333.33333329, 1E30, 4.50, 2e-3, 0.000000000000000000000000001],
3 | "string": "\u20ac$\u000F\u000aA'\u0042\u0022\u005c\\\"\/",
4 | "literals": [null, true, false]
5 | }
--------------------------------------------------------------------------------
/testdata/output/weird.json:
--------------------------------------------------------------------------------
1 | {"\n":"Newline","\r":"Carriage Return","1":"One","":"Browser Challenge","":"Control","ö":"Latin Small Letter O With Diaeresis","€":"Euro Sign","😂":"Smiley","דּ":"Hebrew Letter Dalet With Dagesh"}
--------------------------------------------------------------------------------
/java/canonicalizer/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | json-canonicalization
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/dotnet/es6numberserializer/es6numberserializer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | true
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/testdata/outhex/structures.txt:
--------------------------------------------------------------------------------
1 | 7b 22 22 3a 22 65 6d 70 74 79 22 2c 22 31 22 3a 7b 22 5c 6e 22 3a 35 36 2c 22 66 22 3a 7b 22 46
2 | 22 3a 35 2c 22 66 22 3a 22 68 69 22 7d 7d 2c 22 31 30 22 3a 7b 7d 2c 22 31 31 31 22 3a 5b 7b 22
3 | 45 22 3a 22 6e 6f 22 2c 22 65 22 3a 22 79 65 73 22 7d 5d 2c 22 41 22 3a 7b 7d 2c 22 61 22 3a 7b
4 | 7d 7d
5 |
--------------------------------------------------------------------------------
/testdata/input/weird.json:
--------------------------------------------------------------------------------
1 | {
2 | "\u20ac": "Euro Sign",
3 | "\r": "Carriage Return",
4 | "\u000a": "Newline",
5 | "1": "One",
6 | "\u0080": "Control\u007f",
7 | "\ud83d\ude02": "Smiley",
8 | "\u00f6": "Latin Small Letter O With Diaeresis",
9 | "\ufb33": "Hebrew Letter Dalet With Dagesh",
10 | "": "Browser Challenge"
11 | }
12 |
--------------------------------------------------------------------------------
/dotnet/es6numbercli/es6numbercli.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.1
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/testdata/outhex/values.txt:
--------------------------------------------------------------------------------
1 | 7b 22 6c 69 74 65 72 61 6c 73 22 3a 5b 6e 75 6c 6c 2c 74 72 75 65 2c 66 61 6c 73 65 5d 2c 22 6e
2 | 75 6d 62 65 72 73 22 3a 5b 33 33 33 33 33 33 33 33 33 2e 33 33 33 33 33 33 33 2c 31 65 2b 33 30
3 | 2c 34 2e 35 2c 30 2e 30 30 32 2c 31 65 2d 32 37 5d 2c 22 73 74 72 69 6e 67 22 3a 22 e2 82 ac 24
4 | 5c 75 30 30 30 66 5c 6e 41 27 42 5c 22 5c 5c 5c 5c 5c 22 2f 22 7d
5 |
--------------------------------------------------------------------------------
/dotnet/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: http://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Unix-style newlines with a newline ending every file
7 | [*]
8 | end_of_line = lf
9 | insert_final_newline = true
10 |
11 | # Matches multiple files with brace expansion notation
12 | # Set default charset
13 | [*]
14 | charset = utf-8
15 |
--------------------------------------------------------------------------------
/node-es6/README.md:
--------------------------------------------------------------------------------
1 | ### Node.js canonicalizer + test programs
2 |
3 | For running `verify-numbers.js` you need to download a 3Gb+ file with test
4 | data described in the root directory `testdata`. This file can be stored in
5 | any directory and requires updating the file path in `verify-numbers.js`
6 |
7 |
8 | ```code
9 | $ node verify-canonicalization.js
10 | $ node verify-numbers.js
11 | ```
12 |
--------------------------------------------------------------------------------
/dotnet/jsoncanonicalizer/jsoncanonicalizer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | true
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/testdata/outhex/french.txt:
--------------------------------------------------------------------------------
1 | 7b 22 70 65 61 63 68 22 3a 22 54 68 69 73 20 73 6f 72 74 69 6e 67 20 6f 72 64 65 72 22 2c 22 70
2 | c3 a9 63 68 c3 a9 22 3a 22 69 73 20 77 72 6f 6e 67 20 61 63 63 6f 72 64 69 6e 67 20 74 6f 20 46
3 | 72 65 6e 63 68 22 2c 22 70 c3 aa 63 68 65 22 3a 22 62 75 74 20 63 61 6e 6f 6e 69 63 61 6c 69 7a
4 | 61 74 69 6f 6e 20 4d 55 53 54 22 2c 22 73 69 6e 22 3a 22 69 67 6e 6f 72 65 20 6c 6f 63 61 6c 65
5 | 22 7d
6 |
--------------------------------------------------------------------------------
/dotnet/verify-numbers/verify-numbers.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.1
6 | verify_numbers
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/dotnet/verify-canonicalization/verify-canonicalization.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.1
6 | verify_canonicalization
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/dotnet/es6numberserializer/README.md:
--------------------------------------------------------------------------------
1 | ## ES6 Compatible JSON Number Serialization for .NET
2 |
3 | This project contains a port from Mozilla's JavaScript engine in Java ("Rhino").
4 |
5 | The code has been verified using a test file with a 100 million of random and selected values:
6 | https://onedrive.live.com/embed?cid=9341770E0D0D5468&resid=9341770E0D0D5468%21222&authkey=ADOClRsuPv3_pTk
7 |
8 | The project **verify-es6numberserialization** contains the actual test program.
9 |
--------------------------------------------------------------------------------
/dotnet/json.net.sign/json.net.sign.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.1
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/java/miscellaneous/README.md:
--------------------------------------------------------------------------------
1 | ### Java Test Programs
2 |
3 | This directory contains a number of test programs for the canonicalizer stored in the sibling directory.
4 |
5 | Note that `verify-numbers` require download of a 3Gb+ file with testdata.
6 | See root directory `testdata` for details.
7 | This file can be stored in any suitable place.
8 | After that the file `webpki.properties` must be updated with the actual path.
9 |
10 | ```code
11 | $ ant verify-canonicalization
12 | $ ant verify-numbers
13 | ```
14 |
--------------------------------------------------------------------------------
/JSON.canonify.md:
--------------------------------------------------------------------------------
1 | ## ECMAScript Proposal: JSON.canonify()
2 |
3 | `JSON.canonify()` would inherit all the functionality of `JSON.stringify()` with one signficant change: properties (keys) are *sorted*.
4 | For details on the sorting scheme turn to: https://github.com/cyberphone/json-canonicalization#json-canonicalization
5 |
6 | `JSON.canonify()` is expected to require very modest changes to existing ECMAScript `JSON` object implementations; possibly something along the following:
7 |
8 | ```js
9 | // We are about to serialize an 'Object'
10 | (canonicalizeMode ? Object.keys(object).sort() : Object.keys(object)).forEach((key) => {
11 | ```
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2018 Anders Rundgren
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | https://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/testdata/outhex/weird.txt:
--------------------------------------------------------------------------------
1 | 7b 22 5c 6e 22 3a 22 4e 65 77 6c 69 6e 65 22 2c 22 5c 72 22 3a 22 43 61 72 72 69 61 67 65 20 52
2 | 65 74 75 72 6e 22 2c 22 31 22 3a 22 4f 6e 65 22 2c 22 3c 2f 73 63 72 69 70 74 3e 22 3a 22 42 72
3 | 6f 77 73 65 72 20 43 68 61 6c 6c 65 6e 67 65 22 2c 22 c2 80 22 3a 22 43 6f 6e 74 72 6f 6c 7f 22
4 | 2c 22 c3 b6 22 3a 22 4c 61 74 69 6e 20 53 6d 61 6c 6c 20 4c 65 74 74 65 72 20 4f 20 57 69 74 68
5 | 20 44 69 61 65 72 65 73 69 73 22 2c 22 e2 82 ac 22 3a 22 45 75 72 6f 20 53 69 67 6e 22 2c 22 f0
6 | 9f 98 82 22 3a 22 53 6d 69 6c 65 79 22 2c 22 ef ac b3 22 3a 22 48 65 62 72 65 77 20 4c 65 74 74
7 | 65 72 20 44 61 6c 65 74 20 57 69 74 68 20 44 61 67 65 73 68 22 7d
8 |
--------------------------------------------------------------------------------
/java/canonicalizer/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | canonicalizer
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
19 | 1723925813691
20 |
21 | 30
22 |
23 | org.eclipse.core.resources.regexFilterMatcher
24 | node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/dotnet/README.md:
--------------------------------------------------------------------------------
1 | ## JSON Canonicalizer for .NET
2 |
3 | The [jsoncanonicalizer](jsoncanonicalizer)
4 | folder contains the source code for a JCS (RFC 8785) compliant
5 | canonicalizer written in C# for .NET Core 3 and forward.
6 |
7 | ### Using the JSON canonicalizer
8 |
9 | ```c#
10 | using Org.Webpki.JsonCanonicalizer;
11 |
12 | JsonCanonicalizer jsonCanonicalizer = new JsonCanonicalizer(jsonString);
13 | string result = jsonCanonicalizer.GetEncodedString();
14 |
15 | ```
16 | The `JsonCanonicalizer()` may also be invoked with a `byte[]` array holding JSON data in UTF-8 format.
17 |
18 | In addition to `GetEncodedString()` there is a method `GetEncodedUTF8()` returning canonicalized data as
19 | a `byte[]` array.
20 |
21 | ### Constraints
22 | The JSON canonicalizer only accepts a JSON _Object_ or _Array_ as the top level data type.
23 |
--------------------------------------------------------------------------------
/go/README.md:
--------------------------------------------------------------------------------
1 | ## JSON Canonicalizer for Go
2 |
3 | The [jsoncanonicalizer](src/webpki.org/jsoncanonicalizer)
4 | folder contains the source code for a
5 | JCS (RFC 8785) compliant JSON canonicalizer written in Go.
6 |
7 | ### Building and testing
8 |
9 | - Set GOPATH to this directory.
10 |
11 | - For running `verify-numbers.go` you need to download a 3Gb+ file with test
12 | data described in the root directory [testdata](../testdata). This file can be stored in
13 | any directory and requires updating the file path in `verify-numbers.go`.
14 |
15 | - Perform the commands:
16 | ```code
17 | $ cd test
18 | $ go build webpki.org/jsoncanonicalizer
19 | $ go run verify-canonicalization.go
20 | $ go run verify-numbers.go
21 | ```
22 |
23 |
24 | ### Using the JSON canonicalizer
25 |
26 | ```go
27 | import "webpki.org/jsoncanonicalizer"
28 |
29 | func Transform(jsonData []byte) (result []byte, e error)
30 | ```
31 | Note that both the input and the result is assumed to be in UTF-8 format.
32 |
33 | ### Constraints
34 | The JSON canonicalizer only accepts a JSON _Object_ or _Array_ as the top level data type.
35 |
--------------------------------------------------------------------------------
/python3/README.md:
--------------------------------------------------------------------------------
1 | ## JSON Canonicalizer for Python
2 |
3 | The [src/org/webpki/json](src/org/webpki/json)
4 | folder contains the source code for a
5 | JCS (RFC 8785) compliant canonicalizer written in Python.
6 |
7 | ### Building and testing
8 |
9 | - Set PYTHONPATH to the `src` directory.
10 |
11 | - For running `verify-numbers.py` you need to download a 3Gb+ file with test
12 | data described in the root directory [testdata](../testdata). This file can be stored in
13 | any directory and requires updating the file path in `verify-numbers.py`.
14 |
15 | - Perform the commands:
16 | ```code
17 | $ cd test
18 | $ python verify-canonicalization.py
19 | $ python verify-numbers.py
20 | ```
21 |
22 |
23 | ### Using the JSON canonicalizer
24 |
25 | ```python
26 | from org.webpki.json.Canonicalize import canonicalize
27 |
28 | data = canonicalize({"tag":4})
29 | ```
30 | Note that the input is Python data structures while result is an UTF-8 formatted byte array.
31 |
32 | If you rather need a free-standing canonicalizer you can achive that by using standard Python tools:
33 | ```python
34 | from org.webpki.json.Canonicalize import canonicalize
35 | from json import loads
36 |
37 | data = canonicalize(loads('{"tag":4}'))
38 | ```
39 |
--------------------------------------------------------------------------------
/java/canonicalizer/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
28 |
29 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/java/canonicalizer/README.md:
--------------------------------------------------------------------------------
1 | # JSON Canonicalizer for Java
2 | This library implements the canonicalization scheme described in
3 | the [core](https://github.com/cyberphone/json-canonicalization#json-canonicalization) of this repository.
4 |
5 | A compiled JAR is available in the [dist](dist) sub directory while the source is available in the [src](src) sub directory.
6 |
7 | ### Using the JSON canonicalizer
8 |
9 | ```java
10 | import org.webpki.jcs.JsonCanonicalizer;
11 |
12 | JsonCanonicalizer jsonCanonicalizer = new JsonCanonicalizer(jsonString);
13 | String result = jsonCanonicalizer.getEncodedString();
14 |
15 | ```
16 | The `JsonCanonicalizer()` may also be invoked with a `byte[]` array holding JSON data in UTF-8 format.
17 |
18 | In addition to `getEncodedString()` there is a method `getEncodedUTF8()` returning canonicalized data as
19 | a `byte[]` array.
20 |
21 | ### Constraints
22 | The JSON canonicalizer only accepts a JSON _Object_ or _Array_ as the top level data type.
23 |
24 | ### ES6 Number Formatting
25 | For formatting the JSON Number data type in an ES6 compliant way, there is a static utility method
26 | (which is also used internally by the JSON canonicalizer):
27 | ```java
28 | public static String NumberToJSON.serializeNumber(double value) throws IOException;
29 | ```
30 |
--------------------------------------------------------------------------------
/java/miscellaneous/src/Unicode2UTF16.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2006-2018 WebPKI.org (http://webpki.org).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | import java.util.Scanner;
19 |
20 | public class Unicode2UTF16 {
21 |
22 | public static void main(String[] args) throws Exception {
23 | Scanner input = new Scanner(System.in);
24 | while (true) {
25 | System.out.println("\nEnter uncode code point in hex: ");
26 | String line = input.next();
27 | char[] utf16 = Character.toChars(Integer.parseInt(line, 16));
28 | for (char c : utf16) {
29 | String hex = Integer.toHexString(c);
30 | while (hex.length() < 4) {
31 | hex = "0" + hex;
32 | }
33 | System.out.print(" " + hex);
34 | }
35 | System.out.println();
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/node-es6/verify-canonicalization.js:
--------------------------------------------------------------------------------
1 | // JavaScript source code for testing the JSON canonicalizer
2 |
3 | 'use strict';
4 | const Fs = require('fs');
5 | const canonicalize = require('./canonicalize.js');
6 |
7 | const pathSeparator = __dirname.indexOf('\\') >= 0 ? '\\' : '/';
8 | const rootPath = __dirname.substring(0, __dirname.lastIndexOf(pathSeparator))
9 |
10 | const inputData = rootPath + '/testdata/input';
11 | const outputData = rootPath + '/testdata/output';
12 |
13 | function readFile(path) {
14 | return Fs.readFileSync(path);
15 | }
16 |
17 | var failures = 0;
18 |
19 | Fs.readdirSync(inputData).forEach((fileName) => {
20 | var expected = readFile(outputData + '/' + fileName);
21 | var actual = Buffer.from(canonicalize(JSON.parse(readFile(inputData + '/' + fileName))));
22 | var next = false;
23 | var byteCount = 0;
24 | var utf8 = '\nFile: ' + fileName;
25 | for (let i = 0; i < actual.length; i++) {
26 | if (byteCount++ % 32 == 0) {
27 | utf8 += '\n';
28 | next = false;
29 | }
30 | if (next) {
31 | utf8 += ' ';
32 | }
33 | next = true;
34 | utf8 += actual[i].toString(16);
35 | }
36 | console.log(utf8 + '\n');
37 | if (expected.compare(actual)) {
38 | failures++;
39 | console.log('THE TEST ABOVE FAILED!');
40 | }
41 | });
42 |
43 | if (failures == 0) {
44 | console.log('All tests succeeded!');
45 | } else {
46 | console.log('\n****** ERRORS: ' + failures + ' *******\n');
47 | }
48 |
--------------------------------------------------------------------------------
/java/canonicalizer/src/org/webpki/jcs/NumberToJSON.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 Ulf Adams.
3 | *
4 | * Modifications for ECMAScript / RFC 8785 by Anders Rundgren
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * https://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | */
19 | package org.webpki.jcs;
20 |
21 | import java.io.IOException;
22 |
23 | /**
24 | * JSON as specified by ECMAScript
25 | */
26 | public final class NumberToJSON {
27 | /**
28 | * Formats a number according to ECMAScript.
29 | *
30 | * This code is emulating 7.1.12.1 of the EcmaScript V6 specification.
31 | *
32 | *
33 | * @param value Value to be formatted
34 | * @return String representation
35 | */
36 | public static String serializeNumber(double value) throws IOException {
37 | // First, handle the JSON cases.
38 | if (value == 0.0) {
39 | return "0";
40 | }
41 | if (Double.isNaN(value) || Double.isInfinite(value)) {
42 | throw new IOException("NaN/Infinity not allowed in JSON");
43 | }
44 | return DoubleCoreSerializer.serialize(value, true);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/dotnet/json.net.sign/Int64Converter.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2006-2019 WebPKI.org (http://webpki.org).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | using System;
19 | using System.Text.RegularExpressions;
20 |
21 | using Newtonsoft.Json;
22 |
23 | // Annotation argument for Int64 encoding/decoding
24 |
25 | namespace json.net.signaturesupport
26 | {
27 | public class Int64Converter : JsonConverter
28 | {
29 | static Regex INTEGER_PATTERN = new Regex("^(0|-?[1-9]+[0-9]*)$");
30 |
31 | public override bool CanConvert(Type objectType)
32 | {
33 | return true;
34 | }
35 |
36 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
37 | {
38 | string value = (string)reader.Value;
39 | if (INTEGER_PATTERN.IsMatch(value))
40 | {
41 | return long.Parse(value);
42 | }
43 | throw new ArgumentException("Invalid int64 format: " + value);
44 | }
45 |
46 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
47 | {
48 | writer.WriteValue(((long)value).ToString());
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/REST.signatures.md:
--------------------------------------------------------------------------------
1 | ## REST Signatures
2 |
3 | Since there is no standard for signing REST requests, the industry is currently using
4 | various proprietary solutions mostly based on HTTP bindings and detached data.
5 | This note outlines a simple REST signature scheme.
6 |
7 | ### Unsigned REST Requests
8 |
9 | Assume you have REST system using URIs for holding parameters as well as optionally using the HTTP Body as holder of additional data.
10 |
11 | A REST HTTP request could then look like:
12 |
13 | ```code
14 | POST /foo HTTP/1.1
15 | Host: example.com
16 | Content-Type: application/json
17 | Content-Length: 1234
18 | {
19 | "something": "data",
20 |
21 | Additional application specific properties
22 |
23 | }
24 | ```
25 |
26 | In this scenario the request is qualified by:
27 | - The URI
28 | - The HTTP Verb
29 | - The HTTP Body
30 |
31 | ### Adding a Signature
32 | The following is a modified HTTP Body providing a signed counterpart:
33 |
34 | ```code
35 | {
36 | "something": "data",
37 |
38 | Additional application specific properties
39 |
40 | ".secinf": {
41 | "uri": "https://example.com/foo",
42 | "mtd": "POST",
43 | "iat": 1551709923,
44 | "jws": "eyJhbGciOiJIUzI1NiJ9..VHVItCBCb849imarDtjw4"
45 | }
46 | }
47 | ```
48 | The argument to `jws` would preferably be a JWS in "detached" mode as described in:
49 | https://tools.ietf.org/html/rfc7515#appendix-F
50 |
51 | Before signing, the JWS "payload" (all but the `jws` element), would pass through JCS
52 | (https://tools.ietf.org/html/draft-rundgren-json-canonicalization-scheme-05)
53 | to make the signature insensitive
54 | to whitespace handling and property ordering as well as to *JSON compliant* variances in string and
55 | number formatting.
56 |
57 |
58 | ### Summary
59 | The depicted signature scheme accomplishes the following:
60 | - Signs the core parameters of a REST request
61 | - Maintains clear text messaging using JSON
62 | - Supports proxying and storage in databases without signature breakage
63 | - Enables embedding in other JSON objects for counter signing etc.
64 |
65 | v0.1
66 |
--------------------------------------------------------------------------------
/dotnet/verify-canonicalization/ArrayUtil.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2006-2019 WebPKI.org (http://webpki.org).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | using System.IO;
19 |
20 | namespace VerifyJsonCanonicalizer
21 | {
22 | public static class ArrayUtil
23 | {
24 | public static byte[] ReadFile(string fileName)
25 | {
26 | using (FileStream fsSource = new FileStream(fileName, FileMode.Open, FileAccess.Read))
27 | {
28 | // Read the source file into a byte array.
29 | byte[] bytes = new byte[fsSource.Length];
30 | int numBytesToRead = (int)fsSource.Length;
31 | int numBytesRead = 0;
32 | while (numBytesToRead > 0)
33 | {
34 | // Read may return anything from 0 to numBytesToRead.
35 | int n = fsSource.Read(bytes, numBytesRead, numBytesToRead);
36 |
37 | // Break when the end of the file is reached.
38 | if (n == 0)
39 | break;
40 |
41 | numBytesRead += n;
42 | numBytesToRead -= n;
43 | }
44 | // Write the byte array to memory.
45 | using (MemoryStream result = new MemoryStream())
46 | {
47 | result.Write(bytes, 0, bytes.Length);
48 | return result.ToArray();
49 | }
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/dotnet/json.net.sign/UTCStrictDateConverter.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2006-2019 WebPKI.org (http://webpki.org).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | using System;
19 | using System.Globalization;
20 | using System.Text.RegularExpressions;
21 |
22 | using Newtonsoft.Json;
23 | using Newtonsoft.Json.Converters;
24 |
25 | // Annotation argument for DateTime encoding/decoding
26 |
27 | namespace json.net.signaturesupport
28 | {
29 | public class UTCStrictDateConverter : DateTimeConverterBase
30 | {
31 | static Regex UTC_DATE_NO_FRACTION_PATTERN = new Regex("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$");
32 |
33 | public override bool CanConvert(Type objectType)
34 | {
35 | return true;
36 | }
37 |
38 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
39 | {
40 | DateTime date = ((DateTime)value).ToUniversalTime();
41 | writer.WriteValue(date.ToString("yyyy-MM-dd'T'HH:mm:ss'Z'", CultureInfo.InvariantCulture));
42 | }
43 |
44 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
45 | {
46 | string value = (string)reader.Value;
47 | if (UTC_DATE_NO_FRACTION_PATTERN.IsMatch(value))
48 | {
49 | return DateTime.Parse(value);
50 | }
51 | throw new ArgumentException("Invalid DateTime format: " + value);
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/java/deprecated/org/webpki/jcs/NumberToJSON.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2006-2018 WebPKI.org (http://webpki.org).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 | package org.webpki.jcs;
18 |
19 | import java.io.IOException;
20 |
21 | /**
22 | * Number serialization support.
23 | */
24 | public class NumberToJSON {
25 |
26 | private NumberToJSON() {}
27 |
28 | /**
29 | * Formats a number according to ES6.
30 | * This code is emulating 7.1.12.1 of the EcmaScript V6 specification.
31 | * @param value Value to be formatted
32 | * @return String representation
33 | * @throws IOException
34 | */
35 | public static String serializeNumber(double value) throws IOException {
36 | // 1. Check for JSON compatibility.
37 | if (Double.isNaN(value) || Double.isInfinite(value)) {
38 | throw new IOException("NaN/Infinity are not permitted in JSON");
39 | }
40 |
41 | // 2.Deal with zero separately. Note that this test takes "-0.0" as well
42 | if (value == 0.0) {
43 | return "0";
44 | }
45 |
46 | // 3. Call the DtoA algorithm crunchers
47 | // V8 FastDtoa can't convert all numbers, so try it first but
48 | // fall back to old DToA in case it fails
49 | String result = NumberFastDtoa.numberToString(value);
50 | if (result != null) {
51 | return result;
52 | }
53 | StringBuilder buffer = new StringBuilder();
54 | NumberDToA.JS_dtostr(buffer, NumberDToA.DTOSTR_STANDARD, 0, value);
55 | return buffer.toString();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/node-es6/verify-numbers.js:
--------------------------------------------------------------------------------
1 | // JavaScript source code for testing number parsing and serialization
2 |
3 | 'use strict';
4 | const Fs = require('fs');
5 |
6 | var conversionErrors = 0;
7 |
8 | const INVALID_NUMBER = "null";
9 |
10 | function verify(ieeeHex, expected) {
11 | while (ieeeHex.length < 16) {
12 | ieeeHex = '0' + ieeeHex;
13 | }
14 | var ieeeDouble = Buffer.from(ieeeHex, 'hex').readDoubleBE();
15 | var es6Created = JSON.stringify(ieeeDouble);
16 | if (es6Created == INVALID_NUMBER && expected == INVALID_NUMBER) {
17 | return;
18 | } else if (es6Created == expected && Number(expected) == ieeeDouble) {
19 | return;
20 | }
21 | conversionErrors++;
22 | console.log("Hex=" + ieeeHex + " Expected=" + expected + " Created=" + es6Created);
23 | }
24 |
25 | verify("4340000000000001", "9007199254740994");
26 | verify("4340000000000002", "9007199254740996");
27 | verify("444b1ae4d6e2ef50", "1e+21");
28 | verify("3eb0c6f7a0b5ed8d", "0.000001");
29 | verify("3eb0c6f7a0b5ed8c", "9.999999999999997e-7");
30 | verify("8000000000000000", "0");
31 | verify("7fffffffffffffff", INVALID_NUMBER);
32 | verify("7ff0000000000000", INVALID_NUMBER);
33 | verify("fff0000000000000", INVALID_NUMBER);
34 |
35 | // Change the file name below to fit your environment
36 | var file = Fs.openSync("c:\\es6\\numbers\\es6testfile100m.txt", "r");
37 | var lineCount = 0;
38 | var fileBuffer = Buffer.alloc(1024);
39 | var line = "";
40 | var length = 0;
41 | while (length = Fs.readSync(file, fileBuffer, 0, 1024, null)) {
42 | for (let q = 0; q < length; q++) {
43 | var c = fileBuffer[q];
44 | if (c == 0x0a) {
45 | if (++lineCount % 1000000 == 0) {
46 | console.log("Line: " + lineCount);
47 | }
48 | let comma = line.indexOf(',');
49 | verify(line.substring(0, comma), line.substring(comma + 1));
50 | line = "";
51 | } else {
52 | line += String.fromCharCode(c);
53 | }
54 | }
55 | }
56 | Fs.closeSync(file);
57 | if (conversionErrors) {
58 | console.log("\n****** ERRORS: " + conversionErrors + " *******");
59 | } else {
60 | console.log("\nSuccessful Operation. Lines read: " + lineCount);
61 | }
62 |
--------------------------------------------------------------------------------
/dotnet/json.net.sign/Base64UrlConverter.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2006-2019 WebPKI.org (http://webpki.org).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | using System;
19 |
20 | using Newtonsoft.Json;
21 |
22 | // Annotation argument for Base64Url encoding/decoding
23 |
24 | namespace json.net.signaturesupport
25 | {
26 | public class Base64UrlConverter : JsonConverter
27 | {
28 | public static string Encode(byte[] binary)
29 | {
30 | var output = Convert.ToBase64String(binary);
31 | return output.Split('=')[0].Replace('+', '-').Replace('/', '_');
32 | }
33 |
34 | public static byte[] Decode(string base64url)
35 | {
36 | base64url = base64url.Replace('-', '+').Replace('_', '/');
37 | switch (base64url.Length % 4)
38 | {
39 | case 0: break;
40 | case 2: base64url += "=="; break;
41 | case 3: base64url += "="; break;
42 | default: throw new ArgumentException("input", "Illegal base64url string!");
43 | }
44 | return Convert.FromBase64String(base64url);
45 | }
46 |
47 | public override bool CanConvert(Type objectType)
48 | {
49 | return true;
50 | }
51 |
52 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
53 | {
54 | return Decode((string)reader.Value);
55 | }
56 |
57 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
58 | {
59 | writer.WriteValue(Encode((byte[])value));
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/dotnet/es6numberserializer/NumberToJson.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2006-2018 WebPKI.org (http://webpki.org).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | // Ported to C# from the Mozilla "Rhino" project by Anders Rundgren.
19 |
20 | using System;
21 | using System.Text;
22 |
23 | ///
24 | /// This is the only public class of the ES6 compatible JSON Number serializer.
25 | ///
26 |
27 | namespace Org.Webpki.Es6NumberSerialization
28 | {
29 | public static class NumberToJson
30 | {
31 | /*
32 | * Formats a JSON number according to ES6.
33 | * This code is emulating 7.1.12.1 of the EcmaScript V6 specification.
34 | */
35 | public static string SerializeNumber(double value)
36 | {
37 | // 1. Check for JSON compatibility.
38 | if (Double.IsNaN(value) || Double.IsInfinity(value))
39 | {
40 | throw new ArgumentException("NaN/Infinity are not permitted in JSON");
41 | }
42 |
43 | // 2.Deal with zero separately. Note that this test takes "-0.0" as well
44 | if (value == 0.0)
45 | {
46 | return "0";
47 | }
48 |
49 | // 3. Call the DtoA algorithm crunchers
50 | // V8 FastDtoa can't convert all numbers, so try it first but
51 | // fall back to old DToA in case it fails
52 | String result = NumberFastDToA.NumberToString(value);
53 | if (result != null)
54 | {
55 | return result;
56 | }
57 | StringBuilder buffer = new StringBuilder();
58 | NumberDToA.JS_dtostr(buffer, NumberDToA.DTOSTR_STANDARD, 0, value);
59 | return buffer.ToString();
60 | }
61 | }
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/node-es6/canonicalize.js:
--------------------------------------------------------------------------------
1 | // ES6 based JSON canonicalizer
2 | 'use strict';
3 | var canonicalize = function(object) {
4 |
5 | var buffer = '';
6 | serialize(object);
7 | return buffer;
8 |
9 | function serialize(object) {
10 | if (object === null || typeof object !== 'object' ||
11 | object.toJSON != null) {
12 | /////////////////////////////////////////////////
13 | // Primitive type or toJSON - Use ES6/JSON //
14 | /////////////////////////////////////////////////
15 | buffer += JSON.stringify(object);
16 |
17 | } else if (Array.isArray(object)) {
18 | /////////////////////////////////////////////////
19 | // Array - Maintain element order //
20 | /////////////////////////////////////////////////
21 | buffer += '[';
22 | let next = false;
23 | object.forEach((element) => {
24 | if (next) {
25 | buffer += ',';
26 | }
27 | next = true;
28 | /////////////////////////////////////////
29 | // Array element - Recursive expansion //
30 | /////////////////////////////////////////
31 | serialize(element);
32 | });
33 | buffer += ']';
34 |
35 | } else {
36 | /////////////////////////////////////////////////
37 | // Object - Sort properties before serializing //
38 | /////////////////////////////////////////////////
39 | buffer += '{';
40 | let next = false;
41 | Object.keys(object).sort().forEach((property) => {
42 | if (next) {
43 | buffer += ',';
44 | }
45 | next = true;
46 | ///////////////////////////////////////////////
47 | // Property names are strings - Use ES6/JSON //
48 | ///////////////////////////////////////////////
49 | buffer += JSON.stringify(property);
50 | buffer += ':';
51 | //////////////////////////////////////////
52 | // Property value - Recursive expansion //
53 | //////////////////////////////////////////
54 | serialize(object[property]);
55 | });
56 | buffer += '}';
57 | }
58 | }
59 | };
60 |
61 | module.exports = canonicalize;
62 |
--------------------------------------------------------------------------------
/java/miscellaneous/src/ES6InterActive.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2006-2018 WebPKI.org (http://webpki.org).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | import java.util.Scanner;
19 |
20 | import org.webpki.jcs.NumberToJSON;
21 |
22 | public class ES6InterActive {
23 |
24 | public static void main(String[] args) throws Exception {
25 | Scanner input = new Scanner(System.in);
26 | while (true) {
27 | System.out.println("\nEnter xhhhhhhhhh or floating point number: ");
28 | String line = input.next();
29 | String inputFp = "N/A";
30 | double d;
31 | if (line.startsWith("x")) {
32 | String hex = line.substring(1);
33 | while (hex.length() < 16) {
34 | hex = '0' + hex;
35 | }
36 | d = Double.longBitsToDouble(Long.parseUnsignedLong(hex,16));
37 | } else {
38 | inputFp = line;
39 | d = Double.valueOf(inputFp);
40 | }
41 | long ieee = Double.doubleToRawLongBits(d);
42 | String ieeeHex = Long.toHexString(ieee);
43 | while (ieeeHex.length() < 16) {
44 | ieeeHex = '0' + ieeeHex;
45 | }
46 | String ieeeBin = Long.toBinaryString(ieee);
47 | while (ieeeBin.length() < 64) {
48 | ieeeBin = '0' + ieeeBin;
49 | }
50 | ieeeBin = ieeeBin.substring(0,1) + ' ' +
51 | ieeeBin.substring(1,12) + ' ' +
52 | ieeeBin.substring(12);
53 | String outputFp = NumberToJSON.serializeNumber(d);
54 | System.out.println("\nInput floating point: " + inputFp);
55 | System.out.println("Output floating point: " + outputFp);
56 | System.out.println("Hex value: " + ieeeHex);
57 | System.out.println("Binary value: " + ieeeBin);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/dotnet/es6numbercli/Program.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2006-2019 WebPKI.org (http://webpki.org).
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | using System;
19 | using Org.Webpki.Es6NumberSerialization;
20 |
21 | namespace test
22 | {
23 | class Program
24 | {
25 | static void Main(string[] args)
26 | {
27 | if (args.Length != 1)
28 | {
29 | Console.WriteLine("es6cli {xhhhhhhhhh | floating point number}");
30 | Environment.Exit(0);
31 | }
32 | string inData = args[0];
33 | double value;
34 | if (inData.StartsWith("x"))
35 | {
36 | string origIeeeHex = inData.Substring(1);
37 | while (origIeeeHex.Length < 16)
38 | {
39 | origIeeeHex = '0' + origIeeeHex;
40 | }
41 | ulong origBin = Convert.ToUInt64(origIeeeHex, 16);
42 | value = BitConverter.Int64BitsToDouble((long)origBin);
43 | }
44 | else
45 | {
46 | value = double.Parse(inData, System.Globalization.CultureInfo.InvariantCulture);
47 | }
48 | string es6 = NumberToJson.SerializeNumber(value);
49 | ulong ieeeLong = (ulong)BitConverter.DoubleToInt64Bits(value);
50 | ulong ulongMask = 0x8000000000000000L;
51 | string binary = "";
52 | for (int counter = 0; counter < 64; counter++)
53 | {
54 | binary += (ulongMask & ieeeLong) == 0 ? '0' : '1';
55 | ulongMask >>= 1;
56 | if (counter == 0 || counter == 11)
57 | {
58 | binary += ' ';
59 | }
60 | }
61 | string hex = ieeeLong.ToString("x16");
62 | Console.WriteLine("G17=" + value.ToString("G17") + " Hex=" + hex + " ES6=" + es6 + "\nBinary=" + binary);
63 | }
64 | }
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/go/src/webpki.org/jsoncanonicalizer/es6numfmt.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2006-2019 WebPKI.org (http://webpki.org).
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // https://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | // This package converts numbers in IEEE-754 double precision into the
18 | // format specified for JSON in EcmaScript Version 6 and forward.
19 | // The core application for this is canonicalization:
20 | // https://tools.ietf.org/html/draft-rundgren-json-canonicalization-scheme-02
21 |
22 | package jsoncanonicalizer
23 |
24 | import (
25 | "errors"
26 | "math"
27 | "strconv"
28 | "strings"
29 | )
30 |
31 | const invalidPattern uint64 = 0x7ff0000000000000
32 |
33 | func NumberToJSON(ieeeF64 float64) (res string, err error) {
34 | ieeeU64 := math.Float64bits(ieeeF64)
35 |
36 | // Special case: NaN and Infinity are invalid in JSON
37 | if (ieeeU64 & invalidPattern) == invalidPattern {
38 | return "null", errors.New("Invalid JSON number: " + strconv.FormatUint(ieeeU64, 16))
39 | }
40 |
41 | // Special case: eliminate "-0" as mandated by the ES6-JSON/JCS specifications
42 | if ieeeF64 == 0 { // Right, this line takes both -0 and 0
43 | return "0", nil
44 | }
45 |
46 | // Deal with the sign separately
47 | var sign string = ""
48 | if ieeeF64 < 0 {
49 | ieeeF64 =-ieeeF64
50 | sign = "-"
51 | }
52 |
53 | // ES6 has a unique "g" format
54 | var format byte = 'e'
55 | if ieeeF64 < 1e+21 && ieeeF64 >= 1e-6 {
56 | format = 'f'
57 | }
58 |
59 | // The following should do the trick:
60 | es6Formatted := strconv.FormatFloat(ieeeF64, format, -1, 64)
61 |
62 | // Minor cleanup
63 | exponent := strings.IndexByte(es6Formatted, 'e')
64 | if exponent > 0 {
65 | // Go outputs "1e+09" which must be rewritten as "1e+9"
66 | if es6Formatted[exponent + 2] == '0' {
67 | es6Formatted = es6Formatted[:exponent + 2] + es6Formatted[exponent + 3:]
68 | }
69 | }
70 | return sign + es6Formatted, nil
71 | }
72 |
--------------------------------------------------------------------------------
/python3/src/org/webpki/json/LICENSE.PSF:
--------------------------------------------------------------------------------
1 | PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
2 | --------------------------------------------
3 |
4 | 1. This LICENSE AGREEMENT is between the Python Software Foundation
5 | ("PSF"), and the Individual or Organization ("Licensee") accessing and
6 | otherwise using this software ("Python") in source or binary form and
7 | its associated documentation.
8 |
9 | 2. Subject to the terms and conditions of this License Agreement, PSF hereby
10 | grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
11 | analyze, test, perform and/or display publicly, prepare derivative works,
12 | distribute, and otherwise use Python alone or in any derivative version,
13 | provided, however, that PSF's License Agreement and PSF's notice of copyright,
14 | i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
15 | 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Python Software Foundation; All
16 | Rights Reserved" are retained in Python alone or in any derivative version
17 | prepared by Licensee.
18 |
19 | 3. In the event Licensee prepares a derivative work that is based on
20 | or incorporates Python or any part thereof, and wants to make
21 | the derivative work available to others as provided herein, then
22 | Licensee hereby agrees to include in any such work a brief summary of
23 | the changes made to Python.
24 |
25 | 4. PSF is making Python available to Licensee on an "AS IS"
26 | basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
27 | IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
28 | DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
29 | FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
30 | INFRINGE ANY THIRD PARTY RIGHTS.
31 |
32 | 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
33 | FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
34 | A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
35 | OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
36 |
37 | 6. This License Agreement will automatically terminate upon a material
38 | breach of its terms and conditions.
39 |
40 | 7. Nothing in this License Agreement shall be deemed to create any
41 | relationship of agency, partnership, or joint venture between PSF and
42 | Licensee. This License Agreement does not grant permission to use PSF
43 | trademarks or trade name in a trademark sense to endorse or promote
44 | products or services of Licensee, or any third party.
45 |
46 | 8. By copying, installing or otherwise using Python, Licensee
47 | agrees to be bound by the terms and conditions of this License
48 | Agreement.
49 |
--------------------------------------------------------------------------------
/go/test/verify-canonicalization.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2006-2019 WebPKI.org (http://webpki.org).
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // https://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | // This program verifies the JSON canonicalizer using a test suite
18 | // containing sample data and expected output
19 |
20 | package main
21 |
22 | import (
23 | "fmt"
24 | "io/ioutil"
25 | "runtime"
26 | "path/filepath"
27 | "bytes"
28 | "webpki.org/jsoncanonicalizer"
29 | )
30 |
31 | func check(e error) {
32 | if e != nil {
33 | panic(e)
34 | }
35 | }
36 |
37 | var testdata string
38 |
39 | var failures = 0
40 |
41 | func read(fileName string, directory string) []byte {
42 | data, err := ioutil.ReadFile(filepath.Join(filepath.Join(testdata, directory), fileName))
43 | check(err)
44 | return data
45 | }
46 |
47 | func verify(fileName string) {
48 | actual, err := jsoncanonicalizer.Transform(read(fileName, "input"))
49 | check(err)
50 | recycled, err2 := jsoncanonicalizer.Transform(actual)
51 | check(err2)
52 | expected := read(fileName, "output")
53 | var utf8InHex = "\nFile: " + fileName
54 | var byteCount = 0
55 | var next = false
56 | for _, b := range actual {
57 | if byteCount % 32 == 0 {
58 | utf8InHex = utf8InHex + "\n"
59 | next = false
60 | }
61 | byteCount++
62 | if next {
63 | utf8InHex = utf8InHex + " "
64 | }
65 | next = true
66 | utf8InHex = utf8InHex + fmt.Sprintf("%02x", b)
67 | }
68 | fmt.Println(utf8InHex + "\n")
69 | if !bytes.Equal(actual, expected) || !bytes.Equal(actual, recycled) {
70 | failures++
71 | fmt.Println("THE TEST ABOVE FAILED!");
72 | }
73 | }
74 |
75 | func main() {
76 | _, executable, _, _ := runtime.Caller(0)
77 | testdata = filepath.Join(filepath.Dir(filepath.Dir(filepath.Dir(executable))), "testdata")
78 | fmt.Println(testdata)
79 | files, err := ioutil.ReadDir(filepath.Join(testdata, "input"))
80 | check(err)
81 | for _, file := range files {
82 | verify(file.Name())
83 | }
84 | if failures == 0 {
85 | fmt.Println("All tests succeeded!\n")
86 | } else {
87 | fmt.Printf("\n****** ERRORS: %d *******\n", failures)
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/java/miscellaneous/src/AddEdgeCases.java:
--------------------------------------------------------------------------------
1 | import java.io.FileReader;
2 | import java.io.FileWriter;
3 | import java.io.BufferedReader;
4 |
5 | import java.util.LinkedHashMap;
6 |
7 | import org.webpki.jcs.NumberToJSON;
8 |
9 | public class AddEdgeCases {
10 |
11 | static final int TURNS = 10000000;
12 |
13 | static LinkedHashMap ieeeValues = new LinkedHashMap();
14 |
15 | static void add(long exponent, long mantissa) throws Exception {
16 | long value = (exponent << 52) + mantissa;
17 | String ieeeHex = Long.toHexString(value);
18 | Double ieeeDouble = Double.longBitsToDouble(value);
19 | if (ieeeDouble == 0 || ieeeDouble.isNaN() || ieeeDouble.isInfinite()) {
20 | System.out.println("Dropped value: " + ieeeHex);
21 | return;
22 | }
23 | String es6Number = NumberToJSON.serializeNumber(ieeeDouble);
24 | System.out.println("New " + ieeeHex + " " + es6Number);
25 | ieeeValues.put(ieeeHex, es6Number);
26 | }
27 |
28 | public static void main(String[] args) throws Exception {
29 | // Add something
30 | /*
31 | ieeeValues.put("3eb0c6f7a0b5ed8d", "0.000001");
32 | add(5, 70l);
33 | */
34 | BufferedReader in = new BufferedReader(new FileReader(args[0]));
35 | int q = 0;
36 | long total = 0;
37 | while (true) {
38 | String s = in.readLine();
39 | if (s == null) {
40 | in.close();
41 | System.out.println("\nTest was successful");
42 | if (ieeeValues.isEmpty()) {
43 | System.out.println("\nThere were no new values to add");
44 | return;
45 | }
46 | FileWriter writer = new FileWriter(args[0], true);
47 | for (String ieeeHex : ieeeValues.keySet()) {
48 | writer.write(ieeeHex + "," + ieeeValues.get(ieeeHex) + "\n");
49 | }
50 | writer.close();
51 | return;
52 | }
53 | String hex = s.substring(0, s.indexOf(','));
54 | String text = s.substring(s.indexOf(',') + 1);
55 | if (ieeeValues.containsKey(hex)) {
56 | System.out.println("Duplicate: " + hex);
57 | ieeeValues.remove(hex);
58 | }
59 | while (hex.length() < 16) {
60 | hex = '0' + hex;
61 | }
62 | double d = Double.longBitsToDouble(Long.parseUnsignedLong(hex,16));
63 | String res = NumberToJSON.serializeNumber(d);
64 | if (!res.equals(text)) {
65 | System.out.println("FAIL res=" + res + " d=" + d);
66 | return;
67 | }
68 | total++;
69 | if (q++ == TURNS) {
70 | System.out.println("TURN:" + total + " " + text + " d=" + d);
71 | q = 0;
72 | }
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/dotnet/json.net.sign/README.md:
--------------------------------------------------------------------------------
1 | ## Clear Text Signature Sample Solution
2 |
3 | The sample is based on Newtonsoft's Json.NET API (nowadays recommended by Microsoft).
4 |
5 | The code is _deliberately_ simplistic
6 | with respect to the cryptographic part (using a hard-coded algorithm and key),
7 | while the rest is pretty universal. The system uses a combination
8 | of detached JWS and JCS.
9 |
10 | For creating "signable" JSON objects, developers needs adding a signature property
11 | with a JSON property name of their liking and extending the class with one
12 | constant and one method:
13 | ```c#
14 | public class MyObject : ISigned
15 | {
16 | const String SIGNATURE_PROPERTY = "signature";
17 |
18 | // Other properties
19 |
20 | [JsonProperty(SIGNATURE_PROPERTY, NullValueHandling = NullValueHandling.Ignore)]
21 | public string Signature { get; set; }
22 |
23 | public string GetSignatureProperty()
24 | {
25 | return SIGNATURE_PROPERTY;
26 | }
27 | }
28 | ```
29 |
30 | Expected printout from the sample program:
31 | ```json
32 | {
33 | "id": "johndoe",
34 | "counter": "1000000000007800000",
35 | "time": "2019-01-31T19:09:31Z",
36 | "list": [
37 | "yes",
38 | "no"
39 | ],
40 | "€": true,
41 | "amount": "3.56",
42 | "signature": "eyJhbGciOiJIUzI1NiIsImtpZCI6Im15a2V5In0..WWO6rMoEFG53COKfnR88rUIqHcWCTm1pyDOmq1hUfW8"
43 | }
44 | ```
45 |
46 | ## Signing JSON Arrays
47 | The system also provides support for signing arrays:
48 | ```c#
49 | using System;
50 | using System.Collections.Generic;
51 |
52 | using Newtonsoft.Json;
53 |
54 | using json.net.signaturesupport;
55 |
56 | namespace json.net.sign
57 | {
58 | class Program
59 | {
60 | static void Main(string[] args)
61 | {
62 | // Create an array instance
63 | List