JSON Canonicalization Scheme (JCS)

repository·master·Indexed 41 days ago

https://github.com/cyberphone/json-canonicalization

Implementations of the JSON Canonicalization Scheme (JCS) as defined in RFC 8785 for creating deterministic JSON representations suitable for cryptographic operations. Provides libraries for .NET, Go, Java, Python, and Node.js, featuring ES6-compatible number serialization and lexicographic property sorting.

Tokens
6.5K
Snippets
21
Records
29
Agent score
100%

What's inside JCS

  1. Overview of ES6 Compatible JSON Number Serialization for .NET

    master

    This project provides a .NET implementation of ES6-compatible JSON number serialization. It is a port of the logic used in Mozilla's JavaScript engine (Rhino) to ensure that numbers are serialized in a way that is consistent with ECMAScript standards.

    To ensure correctness, the implementation has been verified against a dataset of 100 million random and selected values.

  2. What is the JSON Canonicalization Scheme (JCS)?

    master

    The JSON Canonicalization Scheme (JCS), defined in RFC 8785, provides a method for serializing JSON data into a unique, deterministic string representation. This is essential for cryptographic operations like hashing and signing, where the target data must remain identical during serialization, transport, or parsing.

    JCS achieves determinism through three main mechanisms:

    1. Primitive Serialization: Uses methods compatible with ECMAScript's JSON.stringify().
    2. Property Sorting: Performs a recursive, lexicographic sorting of JSON Object properties.
    3. Array Handling: JSON Array data is canonicalized, but the original element order is preserved.

    To ensure platform interoperability, the resulting canonical JSON string should be converted to UTF-8.

  3. Use the JSON canonicalizer in Python

    master

    To canonicalize Python data structures according to RFC 8785 (JCS), import the canonicalize function from org.webpki.json.Canonicalize.

    Important details:

    • Input: The function accepts standard Python data structures (e.g., dictionaries, lists).
    • Output: The function returns a UTF-8 formatted bytes object representing the canonicalized JSON.
    from org.webpki.json.Canonicalize import canonicalize
    
    data = canonicalize({"tag":4})
  4. Use the JSON Canonicalizer in Java

    master

    To canonicalize a JSON string or byte array, instantiate JsonCanonicalizer with your input. You can then retrieve the canonicalized result as either a String or a UTF-8 encoded byte[] array.

    Supported Input Types:

    • String containing JSON data.
    • byte[] array holding JSON data in UTF-8 format.

    Supported Output Formats:

    • getEncodedString(): Returns the canonicalized JSON as a String.
    • getEncodedUTF8(): Returns the canonicalized JSON as a byte[] array.
    import org.webpki.jcs.JsonCanonicalizer;
    
    // Canonicalize from a String
    JsonCanonicalizer jsonCanonicalizer = new JsonCanonicalizer(jsonString);
    String result = jsonCanonicalizer.getEncodedString();
    
    // Alternatively, get the result as a byte array
    byte[] utf8Result = jsonCanonicalizer.getEncodedUTF8();
  5. Implement a REST signature scheme using JCS and JWS

    master

    Since there is no single standard for signing REST requests, this scheme uses a detached JWS (JSON Web Signature) embedded within the JSON body to sign the core parameters of a request.

    To implement this scheme:

    1. Identify the request components: The request is qualified by the URI, the HTTP Verb, and the HTTP Body.
    2. Canonicalize the payload: Before signing, take the JSON body (excluding the signature element itself) and pass it through JCS (JSON Canonicalization Scheme). This ensures the signature is insensitive to whitespace, property ordering, and JSON-compliant variances in string/number formatting.
    3. Generate a detached JWS: Create a JWS in "detached" mode (as per RFC 7515 Appendix F) using the canonicalized payload.
    4. Embed the signature: Add a .secinf property to the original JSON object containing the metadata and the JWS string.
    {
      "something": "data",
      "Additional application specific properties": "value",
      ".secinf": {
        "uri": "https://example.com/foo",
        "mtd": "POST",
        "iat": 1551709923,
        "jws": "eyJhbGciOiJIUzI1NiJ9..VHVItCBCb849imarDtjw4"
      }
    }
  6. Build and test the Go JSON canonicalizer

    master

    To build and run the tests for the Go implementation, follow these steps:

    1. Set your GOPATH to the current directory.
    2. (Optional) For running verify-numbers.go, download the 3Gb+ test data file described in the root ../testdata directory and update the file path within verify-numbers.go to point to your local copy.
    3. Execute the following commands from the test directory:
    $ cd test
    $ go build webpki.org/jsoncanonicalizer
    $ go run verify-canonicalization.go
    $ go run verify-numbers.go
  7. Implement the ISigned interface for signable JSON objects

    master

    To create JSON objects that can be signed, your classes must implement the ISigned interface. This involves defining a constant for the signature property name and a method to return it. You should also include a property to hold the signature string, using JsonProperty with NullValueHandling.Ignore to ensure the signature field is omitted when it is null (e.g., before the object is signed).

    public class MyObject : ISigned
    {
        const String SIGNATURE_PROPERTY = "signature";
        
        // Other properties
    
        [JsonProperty(SIGNATURE_PROPERTY, NullValueHandling = NullValueHandling.Ignore)]
        public string Signature { get; set; }
        
        public string GetSignatureProperty()
        {
            return SIGNATURE_PROPERTY;
        }
    }
  8. Build and test the Python JCS implementation

    master

    To build and run the tests for the Python implementation located in src/org/webpki/json:

    1. Set Environment: Set your PYTHONPATH to the src directory.
    2. Large Data Testing: To run verify-numbers.py, you must download the 3Gb+ test data file located in the ../testdata directory. You will need to update the file path within verify-numbers.py to point to your downloaded file.
    3. Run Tests: Navigate to the test directory and execute the verification scripts.
    # Set PYTHONPATH to the src directory first
    $ cd test
    $ python verify-canonicalization.py
    $ python verify-numbers.py