github.com/cyverse/go-irodsclient@v0.13.2/irods/types/data_object_checksum.go (about) 1 package types 2 3 import ( 4 "encoding/base64" 5 "encoding/hex" 6 "fmt" 7 "strings" 8 9 "golang.org/x/xerrors" 10 ) 11 12 // ChecksumAlgorithm determines checksum algorithm 13 type ChecksumAlgorithm string 14 15 const ( 16 // ChecksumAlgorithmSHA1 is for SHA1 17 ChecksumAlgorithmSHA1 ChecksumAlgorithm = "SHA-1" 18 // ChecksumAlgorithmSHA256 is for SHA256 19 ChecksumAlgorithmSHA256 ChecksumAlgorithm = "SHA-256" 20 // ChecksumAlgorithmSHA512 is for SHA512 21 ChecksumAlgorithmSHA512 ChecksumAlgorithm = "SHA-512" 22 // ChecksumAlgorithmADLER32 is for ADLER32 23 ChecksumAlgorithmADLER32 ChecksumAlgorithm = "ADLER-32" 24 // ChecksumAlgorithmMD5 is for MD5 25 ChecksumAlgorithmMD5 ChecksumAlgorithm = "MD5" 26 // ChecksumAlgorithmUnknown is for unknown algorithm 27 ChecksumAlgorithmUnknown ChecksumAlgorithm = "" 28 ) 29 30 // IRODSChecksum contains data object hash information 31 type IRODSChecksum struct { 32 OriginalChecksum string 33 Algorithm ChecksumAlgorithm 34 Checksum []byte 35 } 36 37 // CreateIRODSChecksum creates IRODSChecksum from checksum string 38 func CreateIRODSChecksum(checksumString string) (*IRODSChecksum, error) { 39 if len(checksumString) == 0 { 40 // completely normal 41 return &IRODSChecksum{ 42 OriginalChecksum: "", 43 Algorithm: "", 44 Checksum: nil, 45 }, nil 46 } 47 48 algorithm, checksum, err := ParseIRODSChecksum(checksumString) 49 if err != nil { 50 return nil, xerrors.Errorf("failed to split data object checksum: %w", err) 51 } 52 53 return &IRODSChecksum{ 54 OriginalChecksum: checksumString, 55 Algorithm: algorithm, 56 Checksum: checksum, 57 }, nil 58 } 59 60 // ToString stringifies the object 61 func (checksum *IRODSChecksum) ToString() string { 62 return fmt.Sprintf("<IRODSChecksum %s %x>", checksum.Algorithm, checksum.Checksum) 63 } 64 65 // GetChecksumString returns checksum in string 66 func (checksum *IRODSChecksum) GetChecksumString() string { 67 return hex.EncodeToString(checksum.Checksum) 68 } 69 70 // GetOriginalChecksum returns original checksum in string 71 func (checksum *IRODSChecksum) GetOriginalChecksum() string { 72 return checksum.OriginalChecksum 73 } 74 75 // GetHashAlgorithm returns checksum algorithm 76 func (checksum *IRODSChecksum) GetChecksumAlgorithm() string { 77 return string(checksum.Algorithm) 78 } 79 80 // ParseIRODSChecksum parses iRODS checksum string 81 func ParseIRODSChecksum(checksumString string) (ChecksumAlgorithm, []byte, error) { 82 sp := strings.Split(checksumString, ":") 83 84 if len(sp) == 0 || len(sp) > 2 { 85 return ChecksumAlgorithmUnknown, nil, xerrors.Errorf("unexpected checksum: %v", string(checksumString)) 86 } 87 88 algorithm := "" 89 checksum := "" 90 91 if len(sp) == 1 { 92 algorithm = string(ChecksumAlgorithmMD5) 93 checksum = checksumString 94 } else if len(sp) >= 2 { 95 algorithm = sp[0] 96 checksum = sp[1] 97 } 98 99 switch strings.ToLower(algorithm) { 100 case "sha2": 101 checksumBase64, err := base64.StdEncoding.DecodeString(checksum) 102 if err != nil { 103 return ChecksumAlgorithmUnknown, nil, xerrors.Errorf("failed to base64 decode checksum: %v", err) 104 } 105 106 if len(checksumBase64) == 256/8 { 107 return ChecksumAlgorithmSHA256, checksumBase64, nil 108 } else if len(checksumBase64) == 512/8 { 109 return ChecksumAlgorithmSHA512, checksumBase64, nil 110 } 111 return ChecksumAlgorithmUnknown, nil, xerrors.Errorf("unknown checksum algorithm: %s len %d", algorithm, len(checksumBase64)) 112 case "sha256", strings.ToLower(string(ChecksumAlgorithmSHA256)): 113 checksumBase64, err := base64.StdEncoding.DecodeString(checksum) 114 if err != nil { 115 return ChecksumAlgorithmUnknown, nil, xerrors.Errorf("failed to base64 decode checksum: %v", err) 116 } 117 118 if len(checksumBase64) == 256/8 { 119 return ChecksumAlgorithmSHA256, checksumBase64, nil 120 } 121 return ChecksumAlgorithmUnknown, nil, xerrors.Errorf("unknown checksum algorithm: %s len %d", algorithm, len(checksumBase64)) 122 case "sha512", strings.ToLower(string(ChecksumAlgorithmSHA512)): 123 checksumBase64, err := base64.StdEncoding.DecodeString(checksum) 124 if err != nil { 125 return ChecksumAlgorithmUnknown, nil, xerrors.Errorf("failed to base64 decode checksum: %v", err) 126 } 127 128 if len(checksumBase64) == 512/8 { 129 return ChecksumAlgorithmSHA512, checksumBase64, nil 130 } 131 return ChecksumAlgorithmUnknown, nil, xerrors.Errorf("unknown checksum algorithm: %s len %d", algorithm, len(checksumBase64)) 132 case "sha1", strings.ToLower(string(ChecksumAlgorithmSHA1)): 133 checksumBase64, err := base64.StdEncoding.DecodeString(checksum) 134 if err != nil { 135 return ChecksumAlgorithmUnknown, nil, xerrors.Errorf("failed to base64 decode checksum: %v", err) 136 } 137 138 if len(checksumBase64) == 160/8 { 139 return ChecksumAlgorithmSHA1, checksumBase64, nil 140 } 141 return ChecksumAlgorithmUnknown, nil, xerrors.Errorf("unknown checksum algorithm: %s len %d", algorithm, len(checksumBase64)) 142 case "adler32", strings.ToLower(string(ChecksumAlgorithmADLER32)): 143 checksumHex, err := hex.DecodeString(checksum) 144 if err != nil { 145 return ChecksumAlgorithmUnknown, nil, xerrors.Errorf("failed to hex decode checksum: %v", err) 146 } 147 148 if len(checksumHex) == 32/8 { 149 return ChecksumAlgorithmADLER32, checksumHex, nil 150 } 151 return ChecksumAlgorithmUnknown, nil, xerrors.Errorf("unknown checksum algorithm: %s len %d", algorithm, len(checksumHex)) 152 case strings.ToLower(string(ChecksumAlgorithmMD5)): 153 checksumHex, err := hex.DecodeString(checksum) 154 if err != nil { 155 return ChecksumAlgorithmUnknown, nil, xerrors.Errorf("failed to hex decode checksum: %v", err) 156 } 157 158 if len(checksumHex) == 128/8 { 159 return ChecksumAlgorithmMD5, checksumHex, nil 160 } 161 return ChecksumAlgorithmUnknown, nil, xerrors.Errorf("unknown checksum algorithm: %s len %d", algorithm, len(checksumHex)) 162 default: 163 return ChecksumAlgorithmUnknown, nil, xerrors.Errorf("unknown checksum algorithm: %s", algorithm) 164 } 165 }