001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2021, Connect2id Ltd and contributors. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.openid.connect.sdk.assurance.evidences.attachment; 019 020 021import com.nimbusds.jose.util.Base64; 022import com.nimbusds.oauth2.sdk.ParseException; 023import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 024import net.jcip.annotations.Immutable; 025import net.minidev.json.JSONObject; 026 027import java.security.MessageDigest; 028import java.security.NoSuchAlgorithmException; 029import java.util.Objects; 030 031 032/** 033 * Cryptographic digest. 034 * 035 * <p>Related specifications: 036 * 037 * <ul> 038 * <li>OpenID Connect for Identity Assurance 1.0 039 * </ul> 040 */ 041@Immutable 042public final class Digest { 043 044 045 /** 046 * The hash algorithm. 047 */ 048 private final HashAlgorithm alg; 049 050 051 /** 052 * The hash value. 053 */ 054 private final Base64 value; 055 056 057 /** 058 * Creates a new cryptographic digest. 059 * 060 * @param alg The hash algorithm. Must not be {@code null}. 061 * @param value The hash value. Must not be {@code null}. 062 */ 063 public Digest(final HashAlgorithm alg, final Base64 value) { 064 Objects.requireNonNull(alg); 065 this.alg = alg; 066 Objects.requireNonNull(value); 067 this.value = value; 068 } 069 070 071 /** 072 * Returns the hash algorithm. 073 * 074 * @return The hash algorithm. 075 */ 076 public HashAlgorithm getHashAlgorithm() { 077 return alg; 078 } 079 080 081 /** 082 * Returns the hash value. 083 * 084 * @return the hash value. 085 */ 086 public Base64 getValue() { 087 return value; 088 } 089 090 091 /** 092 * Returns {@code true} if this digest matches the computed for the 093 * specified content. 094 * 095 * @param content The content. Must not be {@code null}. 096 * 097 * @return If {@code true} if the digest matches the content, else 098 * {@code false}. 099 * 100 * @throws NoSuchAlgorithmException If the hash algorithm isn't 101 * supported. 102 */ 103 public boolean matches(final Base64 content) 104 throws NoSuchAlgorithmException { 105 106 Digest computed = Digest.compute(getHashAlgorithm(), content); 107 return this.equals(computed); 108 } 109 110 111 /** 112 * Returns a JSON object representation of this cryptographic digest. 113 * 114 * @return The JSON object. 115 */ 116 public JSONObject toJSONObject() { 117 JSONObject jsonObject = new JSONObject(); 118 jsonObject.put("alg", getHashAlgorithm().getValue()); 119 jsonObject.put("value", getValue().toString()); 120 return jsonObject; 121 } 122 123 124 @Override 125 public boolean equals(Object o) { 126 if (this == o) return true; 127 if (!(o instanceof Digest)) return false; 128 Digest digest = (Digest) o; 129 return alg.equals(digest.alg) && getValue().equals(digest.getValue()); 130 } 131 132 133 @Override 134 public int hashCode() { 135 return Objects.hash(alg, getValue()); 136 } 137 138 139 /** 140 * Computes the digest for the specified content. 141 * 142 * @param alg The hash algorithm. Must not be {@code null}. 143 * @param content The content. Must not be {@code null}. 144 * 145 * @return The digest. 146 * 147 * @throws NoSuchAlgorithmException If the hash algorithm isn't 148 * supported. 149 */ 150 public static Digest compute(final HashAlgorithm alg, final Base64 content) 151 throws NoSuchAlgorithmException { 152 153 return compute(alg, content.decode()); 154 } 155 156 157 /** 158 * Computes the digest for the specified content. 159 * 160 * @param alg The hash algorithm. Must not be {@code null}. 161 * @param content The content. Must not be {@code null}. 162 * 163 * @return The digest. 164 * 165 * @throws NoSuchAlgorithmException If the hash algorithm isn't 166 * supported. 167 */ 168 public static Digest compute(final HashAlgorithm alg, final byte[] content) 169 throws NoSuchAlgorithmException { 170 171 MessageDigest md = MessageDigest.getInstance(alg.getValue().toUpperCase()); 172 byte[] hash = md.digest(content); 173 return new Digest(alg, Base64.encode(hash)); 174 } 175 176 177 /** 178 * Parses a digest from the specified JSON object. 179 * 180 * @param jsonObject The JSON object. 181 * 182 * @return The cryptographic digest. 183 * 184 * @throws ParseException If parsing failed. 185 */ 186 public static Digest parse(final JSONObject jsonObject) 187 throws ParseException { 188 189 HashAlgorithm alg = new HashAlgorithm(JSONObjectUtils.getNonBlankString(jsonObject, "alg")); 190 Base64 value = new Base64(JSONObjectUtils.getNonBlankString(jsonObject, "value")); 191 return new Digest(alg, value); 192 } 193}