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  }