You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by da...@apache.org on 2017/10/11 09:49:10 UTC

[cloudstack] branch master updated: CLOUDSTACK-10046 checksum validation for any java supported Digests-type (#2246)

This is an automated email from the ASF dual-hosted git repository.

dahn pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/master by this push:
     new ed7811a  CLOUDSTACK-10046 checksum validation for any java supported Digests-type (#2246)
ed7811a is described below

commit ed7811a9a2589395fcfe8341b870ef14215e008f
Author: dahn <da...@gmail.com>
AuthorDate: Wed Oct 11 11:49:06 2017 +0200

    CLOUDSTACK-10046 checksum validation for any java supported Digests-type (#2246)
    
    * CLOUDSTACK-10046 digest helper for calculating checksums
    
    * CLOUDSTACK-10046 cleanup unused checksum code
    
    * CLOUDSTACK-10046 padding method proof of concept
    
    * CLOUDSTACK-10046 only compare checksums if old value is valid
    
    * Adding positive and negative tests for md5, sha-1 and sha-256, for xen, vmware and kvm hypervisors.
    KVM Results:
    
     Negative Test Passed - Exception Occurred Under template download ['Traceback (most recent call last):\n', '  File "/Users/bstoyanov/Documents/sb2/cloudstack/test/integration/smoke/test_templates.py", line 189, in test_02_1_create_template_with_checksum_sha1_negative\n    self.download(self.apiclient, template.id)\n', '  File "/Users/bstoyanov/Documents/sb2/cloudstack/test/integration/smoke/test_templates.py", line 260, in download\n    template.status)\n', 'Exception: Failed to down [...]
    === TestName: test_02_1_create_template_with_checksum_sha1_negative | Status : SUCCESS ===
    === TestName: test_02_create_template_with_checksum_sha1 | Status : SUCCESS ===.
     Negative Test Passed - Exception Occurred Under template download ['Traceback (most recent call last):\n', '  File "/Users/bstoyanov/Documents/sb2/cloudstack/test/integration/smoke/test_templates.py", line 203, in test_03_1_create_template_with_checksum_sha256_negative\n    self.download(self.apiclient, template.id)\n', '  File "/Users/bstoyanov/Documents/sb2/cloudstack/test/integration/smoke/test_templates.py", line 260, in download\n    template.status)\n', 'Exception: Failed to do [...]
    === TestName: test_03_1_create_template_with_checksum_sha256_negative | Status : SUCCESS ===
    === TestName: test_03_create_template_with_checksum_sha256 | Status : SUCCESS ===
     Negative Test Passed - Exception Occurred Under template download ['Traceback (most recent call last):\n', '  File "/Users/bstoyanov/Documents/sb2/cloudstack/test/integration/smoke/test_templates.py", line 217, in test_04_1_create_template_with_checksum_md5_negative\n    self.download(self.apiclient, template.id)\n', '  File "/Users/bstoyanov/Documents/sb2/cloudstack/test/integration/smoke/test_templates.py", line 260, in download\n    template.status)\n', 'Exception: Failed to downl [...]
    === TestName: test_04_1_create_template_with_checksum_md5_negative | Status : SUCCESS ===
    === TestName: test_04_create_template_with_checksum_md5 | Status : SUCCESS ===
    
    * CLOUDSTACK-10046 digest helper for calculating checksums
    
    * CLOUDSTACK-10046 cleanup unused checksum code
    
    * CLOUDSTACK-10046 padding method proof of concept
    
    * CLOUDSTACK-10046 only compare checksums if old value is valid
    
    * Adding positive and negative tests for md5, sha-1 and sha-256, for xen, vmware and kvm hypervisors.
    KVM Results:
    
     Negative Test Passed - Exception Occurred Under template download ['Traceback (most recent call last):\n', '  File "/Users/bstoyanov/Documents/sb2/cloudstack/test/integration/smoke/test_templates.py", line 189, in test_02_1_create_template_with_checksum_sha1_negative\n    self.download(self.apiclient, template.id)\n', '  File "/Users/bstoyanov/Documents/sb2/cloudstack/test/integration/smoke/test_templates.py", line 260, in download\n    template.status)\n', 'Exception: Failed to down [...]
    === TestName: test_02_1_create_template_with_checksum_sha1_negative | Status : SUCCESS ===
    === TestName: test_02_create_template_with_checksum_sha1 | Status : SUCCESS ===.
     Negative Test Passed - Exception Occurred Under template download ['Traceback (most recent call last):\n', '  File "/Users/bstoyanov/Documents/sb2/cloudstack/test/integration/smoke/test_templates.py", line 203, in test_03_1_create_template_with_checksum_sha256_negative\n    self.download(self.apiclient, template.id)\n', '  File "/Users/bstoyanov/Documents/sb2/cloudstack/test/integration/smoke/test_templates.py", line 260, in download\n    template.status)\n', 'Exception: Failed to do [...]
    === TestName: test_03_1_create_template_with_checksum_sha256_negative | Status : SUCCESS ===
    === TestName: test_03_create_template_with_checksum_sha256 | Status : SUCCESS ===
     Negative Test Passed - Exception Occurred Under template download ['Traceback (most recent call last):\n', '  File "/Users/bstoyanov/Documents/sb2/cloudstack/test/integration/smoke/test_templates.py", line 217, in test_04_1_create_template_with_checksum_md5_negative\n    self.download(self.apiclient, template.id)\n', '  File "/Users/bstoyanov/Documents/sb2/cloudstack/test/integration/smoke/test_templates.py", line 260, in download\n    template.status)\n', 'Exception: Failed to downl [...]
    === TestName: test_04_1_create_template_with_checksum_md5_negative | Status : SUCCESS ===
    === TestName: test_04_create_template_with_checksum_md5 | Status : SUCCESS ===
    
    * Adding additional test with no checksum added when registering template
    Result:
    test_05_create_template_with_no_checksum (integration.smoke.test_templates.TestCreateTemplateWithChecksum) ... === TestName: test_05_create_template_with_no_checksum | Status : SUCCESS ===
    ok
    
    ----------------------------------------------------------------------
    Ran 1 test in 42.320s
    
    OK
    
    * Fixing negative tests exception handling
    
    * Adding tests for ISO checksum validation and fixing a zero prefix failure test in templates
    
    * CLOUDSTACK-10046 padding
    
    * CLOUDSTACK-10046 usability additions
    
    * yet another IDE artifact hindering checkstyle
---
 api/src/org/apache/cloudstack/api/APICommand.java  |   5 +-
 .../cloudstack/api/AbstractGetUploadParamsCmd.java |   8 +-
 .../org/apache/cloudstack/api/ApiConstants.java    |   6 +
 .../api/command/user/iso/RegisterIsoCmd.java       |   2 +-
 .../command/user/template/RegisterTemplateCmd.java |   2 +-
 .../api/command/user/volume/UploadVolumeCmd.java   |   2 +-
 .../cloud/agent/api/ComputeChecksumCommand.java    |  14 +-
 .../src/com/cloud/template/TemplateManager.java    |   2 +-
 scripts/installer/createtmplt.sh                   |   1 +
 scripts/installer/createvolume.sh                  |   1 +
 scripts/storage/qcow2/createtmplt.sh               |  24 +--
 scripts/storage/qcow2/createvolume.sh              |  24 +--
 scripts/storage/secondary/createtmplt.sh           |  34 +---
 scripts/storage/secondary/createvolume.sh          |   1 +
 .../com/cloud/template/TemplateManagerImpl.java    |   4 +-
 server/src/com/cloud/test/DatabaseConfig.java      |  38 ++--
 .../resource/NfsSecondaryStorageResource.java      | 118 +++++-------
 .../storage/template/DownloadManagerImpl.java      |  76 +++-----
 test/integration/smoke/test_iso.py                 | 166 ++++++++++++++++-
 test/integration/smoke/test_templates.py           | 199 +++++++++++++++++++++
 .../cloudstack/utils/security/ChecksumValue.java   |  86 +++++++++
 .../cloudstack/utils/security/DigestHelper.java    |  96 ++++++++++
 .../utils/security/DigestHelperTest.java           | 102 +++++++++++
 23 files changed, 774 insertions(+), 237 deletions(-)

diff --git a/api/src/org/apache/cloudstack/api/APICommand.java b/api/src/org/apache/cloudstack/api/APICommand.java
index d451e4b..c559be0 100644
--- a/api/src/org/apache/cloudstack/api/APICommand.java
+++ b/api/src/org/apache/cloudstack/api/APICommand.java
@@ -16,8 +16,6 @@
 // under the License.
 package org.apache.cloudstack.api;
 
-import static java.lang.annotation.ElementType.TYPE;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
@@ -25,9 +23,12 @@ import java.lang.annotation.Target;
 import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.api.ResponseObject.ResponseView;
 
+import static java.lang.annotation.ElementType.TYPE;
+
 @Retention(RetentionPolicy.RUNTIME)
 @Target({TYPE})
 public @interface APICommand {
+
     Class<? extends BaseResponse> responseObject();
 
     String name() default "";
diff --git a/api/src/org/apache/cloudstack/api/AbstractGetUploadParamsCmd.java b/api/src/org/apache/cloudstack/api/AbstractGetUploadParamsCmd.java
index df63d74..c82f478 100644
--- a/api/src/org/apache/cloudstack/api/AbstractGetUploadParamsCmd.java
+++ b/api/src/org/apache/cloudstack/api/AbstractGetUploadParamsCmd.java
@@ -18,15 +18,15 @@
  */
 package org.apache.cloudstack.api;
 
+import java.net.URL;
+import java.util.UUID;
+
 import org.apache.cloudstack.api.response.DomainResponse;
 import org.apache.cloudstack.api.response.GetUploadParamsResponse;
 import org.apache.cloudstack.api.response.ProjectResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.log4j.Logger;
 
-import java.net.URL;
-import java.util.UUID;
-
 public abstract class AbstractGetUploadParamsCmd extends BaseCmd {
 
     public static final Logger s_logger = Logger.getLogger(AbstractGetUploadParamsCmd.class.getName());
@@ -42,7 +42,7 @@ public abstract class AbstractGetUploadParamsCmd extends BaseCmd {
             + "to be hosted on")
     private Long zoneId;
 
-    @Parameter(name = ApiConstants.CHECKSUM, type = CommandType.STRING, description = "the MD5 checksum value of this volume/template")
+    @Parameter(name = ApiConstants.CHECKSUM, type = CommandType.STRING, description = "the checksum value of this volume/template " + ApiConstants.CHECKSUM_PARAMETER_PREFIX_DESCRIPTION)
     private String checksum;
 
     @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional accountName. Must be used with domainId.")
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index 0a8a112..2300e68 100644
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -673,6 +673,12 @@ public class ApiConstants {
     public static final String ZONE_ID_LIST = "zoneids";
     public static final String DESTINATION_ZONE_ID_LIST = "destzoneids";
     public static final String ADMIN = "admin";
+    public static final String CHECKSUM_PARAMETER_PREFIX_DESCRIPTION = "The parameter containing the checksum will be considered a MD5sum if it is not prefixed\n"
+            + " and just a plain ascii/utf8 representation of a hexadecimal string. If it is required to\n"
+            + " use another algorithm the hexadecimal string is to be prefixed with a string of the form,\n"
+            + " \"{<algorithm>}\", not including the double quotes. In this <algorithm> is the exact string\n"
+            + " representing the java supported algorithm, i.e. MD5 or SHA-256. Note that java does not\n"
+            + " contain an algorithm called SHA256 or one called sha-256, only SHA-256.";
 
     public enum HostDetails {
         all, capacity, events, stats, min;
diff --git a/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java b/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
index 599aac1..3112287 100644
--- a/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
@@ -94,7 +94,7 @@ public class RegisterIsoCmd extends BaseCmd {
     @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account name. Must be used with domainId.")
     private String accountName;
 
-    @Parameter(name = ApiConstants.CHECKSUM, type = CommandType.STRING, description = "the MD5 checksum value of this ISO")
+    @Parameter(name = ApiConstants.CHECKSUM, type = CommandType.STRING, description = "the checksum value of this ISO. " + ApiConstants.CHECKSUM_PARAMETER_PREFIX_DESCRIPTION)
     private String checksum;
 
     @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "Register ISO for the project")
diff --git a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java
index 9e57574..2bd7b2d 100644
--- a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java
@@ -122,7 +122,7 @@ public class RegisterTemplateCmd extends BaseCmd {
     @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional accountName. Must be used with domainId.")
     private String accountName;
 
-    @Parameter(name = ApiConstants.CHECKSUM, type = CommandType.STRING, description = "the MD5 checksum value of this template")
+    @Parameter(name = ApiConstants.CHECKSUM, type = CommandType.STRING, description = "the checksum value of this template. " + ApiConstants.CHECKSUM_PARAMETER_PREFIX_DESCRIPTION)
     private String checksum;
 
     @Parameter(name = ApiConstants.TEMPLATE_TAG, type = CommandType.STRING, description = "the tag for this template.")
diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java
index 2174961..a48a89b 100644
--- a/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java
@@ -82,7 +82,7 @@ public class UploadVolumeCmd extends BaseAsyncCmd {
     @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional accountName. Must be used with domainId.")
     private String accountName;
 
-    @Parameter(name = ApiConstants.CHECKSUM, type = CommandType.STRING, description = "the MD5 checksum value of this volume")
+    @Parameter(name = ApiConstants.CHECKSUM, type = CommandType.STRING, description = "the checksum value of this volume. " + ApiConstants.CHECKSUM_PARAMETER_PREFIX_DESCRIPTION)
     private String checksum;
 
     @Parameter(name = ApiConstants.IMAGE_STORE_UUID, type = CommandType.STRING, description = "Image store uuid")
diff --git a/core/src/com/cloud/agent/api/ComputeChecksumCommand.java b/core/src/com/cloud/agent/api/ComputeChecksumCommand.java
index 5c8c929..fc7c55d 100644
--- a/core/src/com/cloud/agent/api/ComputeChecksumCommand.java
+++ b/core/src/com/cloud/agent/api/ComputeChecksumCommand.java
@@ -25,6 +25,7 @@ import com.cloud.agent.api.to.DataStoreTO;
 public class ComputeChecksumCommand extends SsCommand {
     private DataStoreTO store;
     private String templatePath;
+    private String algorithm = "MD5";
 
     public ComputeChecksumCommand() {
         super();
@@ -35,6 +36,11 @@ public class ComputeChecksumCommand extends SsCommand {
         this.setStore(store);
     }
 
+    public ComputeChecksumCommand(DataStoreTO store, String templatePath, String algorithm) {
+        this(store,templatePath);
+        this.algorithm = algorithm;
+    }
+
     public String getTemplatePath() {
         return templatePath;
     }
@@ -43,8 +49,12 @@ public class ComputeChecksumCommand extends SsCommand {
         return store;
     }
 
-    public void setStore(DataStoreTO store) {
-        this.store = store;
+
+    public String getAlgorithm() {
+        return algorithm;
     }
 
+    void setStore(DataStoreTO store) {
+        this.store = store;
+    }
 }
diff --git a/engine/components-api/src/com/cloud/template/TemplateManager.java b/engine/components-api/src/com/cloud/template/TemplateManager.java
index 5b2d64a..68c3b58 100644
--- a/engine/components-api/src/com/cloud/template/TemplateManager.java
+++ b/engine/components-api/src/com/cloud/template/TemplateManager.java
@@ -115,7 +115,7 @@ public interface TemplateManager {
 
     DataStore getImageStore(String storeUuid, Long zoneId);
 
-    String getChecksum(DataStore store, String templatePath);
+    String getChecksum(DataStore store, String templatePath, String algorithm);
 
     List<DataStore> getImageStoreByTemplate(long templateId, Long zoneId);
 
diff --git a/scripts/installer/createtmplt.sh b/scripts/installer/createtmplt.sh
index 67b25c3..c187c5f 100755
--- a/scripts/installer/createtmplt.sh
+++ b/scripts/installer/createtmplt.sh
@@ -39,6 +39,7 @@ fi
 
 verify_cksum() {
   digestalgo=""
+# NOTE this will only work with 0-padded checksums
   case ${#1} in
         32) digestalgo="md5sum" ;;
         40) digestalgo="sha1sum" ;;
diff --git a/scripts/installer/createvolume.sh b/scripts/installer/createvolume.sh
index 00ee5e5..c7f11dc 100755
--- a/scripts/installer/createvolume.sh
+++ b/scripts/installer/createvolume.sh
@@ -40,6 +40,7 @@ fi
 
 verify_cksum() {
   digestalgo=""
+# NOTE this will only work with 0-padded checksums
   case ${#1} in
         32) digestalgo="md5sum" ;;
         40) digestalgo="sha1sum" ;;
diff --git a/scripts/storage/qcow2/createtmplt.sh b/scripts/storage/qcow2/createtmplt.sh
index 1164525..b05550c 100755
--- a/scripts/storage/qcow2/createtmplt.sh
+++ b/scripts/storage/qcow2/createtmplt.sh
@@ -21,7 +21,7 @@
 # createtmplt.sh -- install a template
 
 usage() {
-  printf "Usage: %s: -t <template-fs> -n <templatename> -f <root disk file> -s <size in Gigabytes> -c <md5 cksum> -d <descr> -h  [-u]\n" $(basename $0) >&2
+  printf "Usage: %s: -t <template-fs> -n <templatename> -f <root disk file> -s <size in Gigabytes> -c <snapshot name> -d <descr> -h  [-u]\n" $(basename $0) >&2
 }
 
 
@@ -37,27 +37,6 @@ then
    fi
 fi
 
-
-verify_cksum() {
-  digestalgo=""
-  case ${#1} in
-        32) digestalgo="md5sum" ;;
-        40) digestalgo="sha1sum" ;;
-        56) digestalgo="sha224sum" ;;
-        64) digestalgo="sha256sum" ;;
-        96) digestalgo="sha384sum" ;;
-        128) digestalgo="sha512sum" ;;
-        *) echo "Please provide valid cheksum" ; exit 3 ;;
-  esac
-  echo  "$1  $2" | $digestalgo  -c --status
-  #printf "$1\t$2" | $digestalgo  -c --status
-  if [ $? -gt 0 ] 
-  then
-    printf "Checksum failed, not proceeding with install\n"
-    exit 3
-  fi
-}
-
 untar() {
   local ft=$(file $1| awk -F" " '{print $2}')
   local basedir=$(dirname $1)
@@ -166,7 +145,6 @@ do
 		tmpltimg="$OPTARG"
 		;;
   s)	sflag=1
-		sflag=1
 		;;
   c)	cflag=1
 		snapshotName="$OPTARG"
diff --git a/scripts/storage/qcow2/createvolume.sh b/scripts/storage/qcow2/createvolume.sh
index 91a7632..033cc91 100755
--- a/scripts/storage/qcow2/createvolume.sh
+++ b/scripts/storage/qcow2/createvolume.sh
@@ -22,7 +22,7 @@
 # createvol.sh -- install a volume
 
 usage() {
-  printf "Usage: %s: -t <volume-fs> -n <volumename> -f <root disk file> -s <size in Gigabytes> -c <md5 cksum> -d <descr> -h  [-u]\n" $(basename $0) >&2
+  printf "Usage: %s: -t <volume-fs> -n <volumename> -f <root disk file> -s <size in Gigabytes> -c <snapshot name> -d <descr> -h  [-u]\n" $(basename $0) >&2
 }
 
 
@@ -38,27 +38,6 @@ then
    fi
 fi
 
-
-verify_cksum() {
-  digestalgo=""
-  case ${#1} in
-        32) digestalgo="md5sum" ;;
-        40) digestalgo="sha1sum" ;;
-        56) digestalgo="sha224sum" ;;
-        64) digestalgo="sha256sum" ;;
-        96) digestalgo="sha384sum" ;;
-        128) digestalgo="sha512sum" ;;
-        *) echo "Please provide valid cheksum" ; exit 3 ;;
-  esac
-  echo  "$1  $2" | $digestalgo  -c --status
-  #printf "$1\t$2" | $digestalgo  -c --status
-  if [ $? -gt 0 ] 
-  then
-    printf "Checksum failed, not proceeding with install\n"
-    exit 3
-  fi
-}
-
 untar() {
   local ft=$(file $1| awk -F" " '{print $2}')
   local basedir=$(dirname $1)
@@ -167,7 +146,6 @@ do
 		volimg="$OPTARG"
 		;;
   s)	sflag=1
-		sflag=1
 		;;
   c)	cflag=1
 		snapshotName="$OPTARG"
diff --git a/scripts/storage/secondary/createtmplt.sh b/scripts/storage/secondary/createtmplt.sh
index acc4ef5..4e8db46 100755
--- a/scripts/storage/secondary/createtmplt.sh
+++ b/scripts/storage/secondary/createtmplt.sh
@@ -22,7 +22,7 @@
 # createtmplt.sh -- install a template
 
 usage() {
-  printf "Usage: %s: -t <template-fs> -n <templatename> -f <root disk file> -c <md5 cksum> -d <descr> -h  [-u] [-v]\n" $(basename $0) >&2
+  printf "Usage: %s: -t <template-fs> -n <templatename> -f <root disk file> -d <descr> -h  [-u] [-v]\n" $(basename $0) >&2
 }
 
 
@@ -39,26 +39,6 @@ rollback_if_needed() {
 fi
 }
 
-verify_cksum() {
-  digestalgo=""
-  case ${#1} in
-        32) digestalgo="md5sum" ;;
-        40) digestalgo="sha1sum" ;;
-        56) digestalgo="sha224sum" ;;
-        64) digestalgo="sha256sum" ;;
-        96) digestalgo="sha384sum" ;;
-        128) digestalgo="sha512sum" ;;
-        *) echo "Please provide valid cheksum" ; exit 3 ;;
-  esac
-  echo  "$1  $2" | $digestalgo  -c --status
-  #printf "$1\t$2" | $digestalgo  -c --status
-  if [ $? -gt 0 ] 
-  then
-    printf "Checksum failed, not proceeding with install\n"
-    exit 3
-  fi
-}
-
 untar() {
   local ft=$(file $1| awk -F" " '{print $2}')
   case $ft in
@@ -138,9 +118,8 @@ hflag=
 hvm=false
 cleanup=false
 dflag=
-cflag=
 
-while getopts 'vuht:n:f:s:c:d:S:' OPTION
+while getopts 'vuht:n:f:s:d:S:' OPTION
 do
   case $OPTION in
   t)	tflag=1
@@ -154,9 +133,6 @@ do
 		;;
   s)	sflag=1
 		;;
-  c)	cflag=1
-		cksum="$OPTARG"
-		;;
   d)	dflag=1
 		descr="$OPTARG"
 		;;
@@ -200,10 +176,6 @@ then
   exit 3
 fi
 
-if [ -n "$cksum" ]
-then
-  verify_cksum $cksum $tmpltimg
-fi
 [ -n "$verbose" ] && is_compressed $tmpltimg
 tmpltimg2=$(uncompress $tmpltimg)
 rollback_if_needed $tmpltfs $? "failed to uncompress $tmpltimg\n"
@@ -236,6 +208,8 @@ echo -n "" > /$tmpltfs/template.properties
 today=$(date '+%m_%d_%Y')
 echo "filename=$tmpltname" > /$tmpltfs/template.properties
 echo "description=$descr" >> /$tmpltfs/template.properties
+# we need to rethink this property as it might get changed after download due to decompression
+# option is to recalcutate it here
 echo "checksum=$cksum" >> /$tmpltfs/template.properties
 echo "hvm=$hvm" >> /$tmpltfs/template.properties
 echo "size=$imgsize" >> /$tmpltfs/template.properties
diff --git a/scripts/storage/secondary/createvolume.sh b/scripts/storage/secondary/createvolume.sh
index c7836dc..12f73eb 100755
--- a/scripts/storage/secondary/createvolume.sh
+++ b/scripts/storage/secondary/createvolume.sh
@@ -41,6 +41,7 @@ fi
 
 verify_cksum() {
   digestalgo=""
+# NOTE this will only work with 0-padded checksums
   case ${#1} in
         32) digestalgo="md5sum" ;;
         40) digestalgo="sha1sum" ;;
diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java
index 86f687c..f6494c3 100644
--- a/server/src/com/cloud/template/TemplateManagerImpl.java
+++ b/server/src/com/cloud/template/TemplateManagerImpl.java
@@ -673,9 +673,9 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
     }
 
     @Override
-    public String getChecksum(DataStore store, String templatePath) {
+    public String getChecksum(DataStore store, String templatePath, String algorithm) {
         EndPoint ep = _epSelector.select(store);
-        ComputeChecksumCommand cmd = new ComputeChecksumCommand(store.getTO(), templatePath);
+        ComputeChecksumCommand cmd = new ComputeChecksumCommand(store.getTO(), templatePath, algorithm);
         Answer answer = null;
         if (ep == null) {
             String errMsg = "No remote endpoint to send command, check if host or ssvm is down?";
diff --git a/server/src/com/cloud/test/DatabaseConfig.java b/server/src/com/cloud/test/DatabaseConfig.java
index a27f671..7240374 100644
--- a/server/src/com/cloud/test/DatabaseConfig.java
+++ b/server/src/com/cloud/test/DatabaseConfig.java
@@ -18,9 +18,7 @@ package com.cloud.test;
 
 import java.io.File;
 import java.io.IOException;
-import java.math.BigInteger;
 import java.net.URISyntaxException;
-import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.sql.Date;
 import java.sql.PreparedStatement;
@@ -39,21 +37,12 @@ import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 
-import org.apache.log4j.Logger;
-import org.apache.log4j.xml.DOMConfigurator;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-
 import com.cloud.host.Status;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDaoImpl;
 import com.cloud.storage.DiskOfferingVO;
-import com.cloud.storage.dao.DiskOfferingDaoImpl;
 import com.cloud.storage.Storage.ProvisioningType;
+import com.cloud.storage.dao.DiskOfferingDaoImpl;
 import com.cloud.utils.PropertiesUtil;
 import com.cloud.utils.component.ComponentContext;
 import com.cloud.utils.db.DB;
@@ -62,6 +51,15 @@ import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
 import com.cloud.utils.db.TransactionLegacy;
 import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.net.NfsUtils;
+import org.apache.cloudstack.utils.security.DigestHelper;
+import org.apache.log4j.Logger;
+import org.apache.log4j.xml.DOMConfigurator;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
 
 public class DatabaseConfig {
     private static final Logger s_logger = Logger.getLogger(DatabaseConfig.class.getName());
@@ -1169,22 +1167,14 @@ public class DatabaseConfig {
             printError("An email address for each user is required.");
         }
 
-        MessageDigest md5 = null;
+        String algorithm = "MD5";
+        String pwDigest;
         try {
-            md5 = MessageDigest.getInstance("MD5");
+            pwDigest = DigestHelper.getPaddedDigest(algorithm, password);
         } catch (NoSuchAlgorithmException e) {
             s_logger.error("error saving user", e);
             return;
         }
-        md5.reset();
-        BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes()));
-        String pwStr = pwInt.toString(16);
-        int padding = 32 - pwStr.length();
-        StringBuffer sb = new StringBuffer();
-        for (int i = 0; i < padding; i++) {
-            sb.append('0'); // make sure the MD5 password is 32 digits long
-        }
-        sb.append(pwStr);
 
         // create an account for the admin user first
         final String insertAdminAccount = "INSERT INTO `cloud`.`account` (id, account_name, type, domain_id) VALUES (?, ?, '1', '1')";
@@ -1206,7 +1196,7 @@ public class DatabaseConfig {
             PreparedStatement stmt = txn.prepareAutoCloseStatement(insertUser);
             stmt.setLong(1, id);
             stmt.setString(2, username);
-            stmt.setString(3, sb.toString());
+            stmt.setString(3, pwDigest);
             stmt.setString(4, firstname);
             stmt.setString(5, lastname);
             stmt.setString(6, email);
diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
index 68569ea..37cb728 100644
--- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
+++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
@@ -16,12 +16,6 @@
 // under the License.
 package org.apache.cloudstack.storage.resource;
 
-import static com.cloud.utils.StringUtils.join;
-import static com.cloud.utils.storage.S3.S3Utils.putFile;
-import static java.lang.String.format;
-import static java.util.Arrays.asList;
-import static org.apache.commons.lang.StringUtils.substringAfterLast;
-
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.File;
@@ -32,11 +26,9 @@ import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
-import java.math.BigInteger;
 import java.net.InetAddress;
 import java.net.URI;
 import java.net.UnknownHostException;
-import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -46,41 +38,6 @@ import java.util.UUID;
 
 import javax.naming.ConfigurationException;
 
-import org.apache.cloudstack.framework.security.keystore.KeystoreManager;
-import org.apache.cloudstack.storage.command.CopyCmdAnswer;
-import org.apache.cloudstack.storage.command.CopyCommand;
-import org.apache.cloudstack.storage.command.DeleteCommand;
-import org.apache.cloudstack.storage.command.DownloadCommand;
-import org.apache.cloudstack.storage.command.DownloadProgressCommand;
-import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand;
-import org.apache.cloudstack.storage.command.UploadStatusAnswer;
-import org.apache.cloudstack.storage.command.UploadStatusAnswer.UploadStatus;
-import org.apache.cloudstack.storage.command.UploadStatusCommand;
-import org.apache.cloudstack.storage.template.DownloadManager;
-import org.apache.cloudstack.storage.template.DownloadManagerImpl;
-import org.apache.cloudstack.storage.template.DownloadManagerImpl.ZfsPathParser;
-import org.apache.cloudstack.storage.template.UploadEntity;
-import org.apache.cloudstack.storage.template.UploadManager;
-import org.apache.cloudstack.storage.template.UploadManagerImpl;
-import org.apache.cloudstack.storage.to.SnapshotObjectTO;
-import org.apache.cloudstack.storage.to.TemplateObjectTO;
-import org.apache.cloudstack.storage.to.VolumeObjectTO;
-import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.utils.URLEncodedUtils;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.log4j.Logger;
-import org.joda.time.DateTime;
-import org.joda.time.format.ISODateTimeFormat;
-
 import com.amazonaws.services.s3.model.S3ObjectSummary;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.CheckHealthAnswer;
@@ -148,7 +105,6 @@ import com.cloud.utils.storage.S3.S3Utils;
 import com.cloud.vm.SecondaryStorageVm;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
-
 import io.netty.bootstrap.ServerBootstrap;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelInitializer;
@@ -162,6 +118,47 @@ import io.netty.handler.codec.http.HttpRequestDecoder;
 import io.netty.handler.codec.http.HttpResponseEncoder;
 import io.netty.handler.logging.LogLevel;
 import io.netty.handler.logging.LoggingHandler;
+import org.apache.cloudstack.framework.security.keystore.KeystoreManager;
+import org.apache.cloudstack.storage.command.CopyCmdAnswer;
+import org.apache.cloudstack.storage.command.CopyCommand;
+import org.apache.cloudstack.storage.command.DeleteCommand;
+import org.apache.cloudstack.storage.command.DownloadCommand;
+import org.apache.cloudstack.storage.command.DownloadProgressCommand;
+import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand;
+import org.apache.cloudstack.storage.command.UploadStatusAnswer;
+import org.apache.cloudstack.storage.command.UploadStatusAnswer.UploadStatus;
+import org.apache.cloudstack.storage.command.UploadStatusCommand;
+import org.apache.cloudstack.storage.template.DownloadManager;
+import org.apache.cloudstack.storage.template.DownloadManagerImpl;
+import org.apache.cloudstack.storage.template.DownloadManagerImpl.ZfsPathParser;
+import org.apache.cloudstack.storage.template.UploadEntity;
+import org.apache.cloudstack.storage.template.UploadManager;
+import org.apache.cloudstack.storage.template.UploadManagerImpl;
+import org.apache.cloudstack.storage.to.SnapshotObjectTO;
+import org.apache.cloudstack.storage.to.TemplateObjectTO;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
+import org.apache.cloudstack.utils.security.DigestHelper;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.log4j.Logger;
+import org.joda.time.DateTime;
+import org.joda.time.format.ISODateTimeFormat;
+
+import static com.cloud.utils.StringUtils.join;
+import static com.cloud.utils.storage.S3.S3Utils.putFile;
+import static java.lang.String.format;
+import static java.util.Arrays.asList;
+import static org.apache.commons.lang.StringUtils.substringAfterLast;
 
 public class NfsSecondaryStorageResource extends ServerResourceBase implements SecondaryStorageResource {
 
@@ -1316,46 +1313,24 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
             parent += File.separator;
         }
         String absoluteTemplatePath = parent + relativeTemplatePath;
-        MessageDigest digest;
-        String checksum = null;
+        String algorithm = cmd.getAlgorithm();
         File f = new File(absoluteTemplatePath);
-        InputStream is = null;
-        byte[] buffer = new byte[8192];
-        int read = 0;
         if (s_logger.isDebugEnabled()) {
             s_logger.debug("parent path " + parent + " relative template path " + relativeTemplatePath);
         }
+        String checksum = null;
 
-        try {
-            digest = MessageDigest.getInstance("MD5");
-            is = new FileInputStream(f);
-            while ((read = is.read(buffer)) > 0) {
-                digest.update(buffer, 0, read);
-            }
-            byte[] md5sum = digest.digest();
-            BigInteger bigInt = new BigInteger(1, md5sum);
-            checksum = bigInt.toString(16);
+        try (InputStream is = new FileInputStream(f);){
+            checksum = DigestHelper.digest(algorithm, is).toString();
             if (s_logger.isDebugEnabled()) {
                 s_logger.debug("Successfully calculated checksum for file " + absoluteTemplatePath + " - " + checksum);
             }
-
         } catch (IOException e) {
-            String logMsg = "Unable to process file for MD5 - " + absoluteTemplatePath;
+            String logMsg = "Unable to process file for " + algorithm + " - " + absoluteTemplatePath;
             s_logger.error(logMsg);
             return new Answer(cmd, false, checksum);
         } catch (NoSuchAlgorithmException e) {
             return new Answer(cmd, false, checksum);
-        } finally {
-            try {
-                if (is != null) {
-                    is.close();
-                }
-            } catch (IOException e) {
-                if (s_logger.isDebugEnabled()) {
-                    s_logger.debug("Could not close the file " + absoluteTemplatePath);
-                }
-                return new Answer(cmd, false, checksum);
-            }
         }
 
         return new Answer(cmd, true, checksum);
@@ -3054,4 +3029,5 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
         }
         return cmd;
     }
+
 }
diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java
index 40a1e1c..833ef09 100644
--- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java
+++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java
@@ -21,10 +21,8 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.math.BigInteger;
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -84,6 +82,8 @@ import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.script.OutputInterpreter;
 import com.cloud.utils.script.Script;
 import com.cloud.utils.storage.QCOW2Utils;
+import org.apache.cloudstack.utils.security.ChecksumValue;
+import org.apache.cloudstack.utils.security.DigestHelper;
 
 public class DownloadManagerImpl extends ManagerBase implements DownloadManager {
     private String _name;
@@ -315,33 +315,11 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager
         }
     }
 
-    private String computeCheckSum(File f) {
-        byte[] buffer = new byte[8192];
-        int read = 0;
-        MessageDigest digest;
-        String checksum = null;
-        InputStream is = null;
-        try {
-            digest = MessageDigest.getInstance("MD5");
-            is = new FileInputStream(f);
-            while ((read = is.read(buffer)) > 0) {
-                digest.update(buffer, 0, read);
-            }
-            byte[] md5sum = digest.digest();
-            BigInteger bigInt = new BigInteger(1, md5sum);
-            checksum = String.format("%032x", bigInt);
-            return checksum;
+    private ChecksumValue computeCheckSum(String algorithm, File f) throws NoSuchAlgorithmException {
+        try (InputStream is = new FileInputStream(f);) {
+            return DigestHelper.digest(algorithm, is);
         } catch (IOException e) {
             return null;
-        } catch (NoSuchAlgorithmException e) {
-            return null;
-        } finally {
-            try {
-                if (is != null)
-                    is.close();
-            } catch (IOException e) {
-                return null;
-            }
         }
     }
 
@@ -357,12 +335,8 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager
             // The QCOW2 is the only format with a header,
             // and as such can be easily read.
 
-            try {
-                InputStream inputStream = td.getS3ObjectInputStream();
-
+            try (InputStream inputStream = td.getS3ObjectInputStream();) {
                 dnld.setTemplatesize(QCOW2Utils.getVirtualSize(inputStream));
-
-                inputStream.close();
             }
             catch (IOException e) {
                 result = "Couldn't read QCOW2 virtual size. Error: " + e.getMessage();
@@ -398,11 +372,22 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager
         ResourceType resourceType = dnld.getResourceType();
 
         File originalTemplate = new File(td.getDownloadLocalPath());
-        String checkSum = computeCheckSum(originalTemplate);
-        if (checkSum == null) {
+        ChecksumValue oldValue = new ChecksumValue(dnld.getChecksum());
+        ChecksumValue newValue = null;
+        try {
+            newValue = computeCheckSum(oldValue.getAlgorithm(), originalTemplate);
+        } catch (NoSuchAlgorithmException e) {
+            return "checksum algorithm not recognised: " + oldValue.getAlgorithm();
+        }
+        if(StringUtils.isNotBlank(dnld.getChecksum()) && ! oldValue.equals(newValue)) {
+            return "checksum \"" + newValue +"\" didn't match the given value, \"" + oldValue + "\"";
+        }
+        String checksum = newValue.getChecksum();
+        if (checksum == null) {
             s_logger.warn("Something wrong happened when try to calculate the checksum of downloaded template!");
         }
-        dnld.setCheckSum(checkSum);
+
+        dnld.setCheckSum(checksum);
 
         int imgSizeGigs = (int)Math.ceil(_storage.getSize(td.getDownloadLocalPath()) * 1.0d / (1024 * 1024 * 1024));
         imgSizeGigs++; // add one just in case
@@ -435,11 +420,7 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager
         scr.add("-n", templateFilename);
 
         scr.add("-t", resourcePath);
-        scr.add("-f", td.getDownloadLocalPath()); // this is the temporary
-        // template file downloaded
-        if (dnld.getChecksum() != null && dnld.getChecksum().length() > 1) {
-            scr.add("-c", dnld.getChecksum());
-        }
+        scr.add("-f", td.getDownloadLocalPath()); // this is the temporary template file downloaded
         scr.add("-u"); // cleanup
         String result;
         result = scr.execute();
@@ -707,6 +688,10 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager
             return new DownloadAnswer("Invalid Name", VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR);
         }
 
+        if(! DigestHelper.isAlgorithmSupported(cmd.getChecksum())) {
+            return new DownloadAnswer("invalid algorithm: " + cmd.getChecksum(), VMTemplateStorageResourceAssoc.Status.NOT_DOWNLOADED);
+        }
+
         DataStoreTO dstore = cmd.getDataStore();
         String installPathPrefix = cmd.getInstallPath();
         // for NFS, we need to get mounted path
@@ -865,17 +850,6 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager
             result.put(tInfo.getTemplateName(), tInfo);
             s_logger.debug("Added template name: " + tInfo.getTemplateName() + ", path: " + tmplt);
         }
-        /*
-        for (String tmplt : isoTmplts) {
-            String tmp[];
-            tmp = tmplt.split("/");
-            String tmpltName = tmp[tmp.length - 2];
-            tmplt = tmplt.substring(tmplt.lastIndexOf("iso/"));
-            TemplateInfo tInfo = new TemplateInfo(tmpltName, tmplt, false);
-            s_logger.debug("Added iso template name: " + tmpltName + ", path: " + tmplt);
-            result.put(tmpltName, tInfo);
-        }
-         */
         return result;
     }
 
diff --git a/test/integration/smoke/test_iso.py b/test/integration/smoke/test_iso.py
index f55f818..afd540a 100755
--- a/test/integration/smoke/test_iso.py
+++ b/test/integration/smoke/test_iso.py
@@ -17,8 +17,10 @@
 """ BVT tests for Templates ISO
 """
 # Import Local Modules
+from marvin.cloudstackException import GetDetailExceptionInfo
 from marvin.cloudstackTestCase import cloudstackTestCase, unittest
-from marvin.cloudstackAPI import listZones, updateIso, extractIso, updateIsoPermissions, copyIso, deleteIso
+from marvin.cloudstackAPI import listZones, updateIso, extractIso, updateIsoPermissions, copyIso, deleteIso,\
+    registerIso,listOsTypes
 from marvin.lib.utils import cleanup_resources, random_gen, get_hypervisor_type,validateList
 from marvin.lib.base import Account, Iso
 from marvin.lib.common import (get_domain,
@@ -606,3 +608,165 @@ class TestISO(cloudstackTestCase):
         self.get_iso_details("vmware-tools.iso")
         self.get_iso_details("xs-tools.iso")
         return
+
+
+class TestCreateISOWithChecksum(cloudstackTestCase):
+    def setUp(self):
+        self.testClient = super(TestCreateISOWithChecksum, self).getClsTestClient()
+        self.apiclient = self.testClient.getApiClient()
+        self.cleanup = []
+
+        self.unsupportedHypervisor = False
+        self.hypervisor = self.testClient.getHypervisorInfo()
+        if self.hypervisor.lower() in ['lxc']:
+            # Template creation from root volume is not supported in LXC
+            self.unsupportedHypervisor = True
+            return
+
+        # Get Zone, Domain and templates
+        self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests())
+
+        # Setup default create iso attributes
+        self.iso = registerIso.registerIsoCmd()
+        self.iso.checksum = "{SHA-1}" + "e16f703b5d6cb6dd2c448d956be63fcbee7d79ea"
+        self.iso.zoneid = self.zone.id
+        self.iso.name = 'test-tynyCore-iso'
+        self.iso.displaytext = 'test-tynyCore-iso'
+        self.iso.url = "http://dl.openvm.eu/cloudstack/iso/TinyCore-8.0.iso"
+        self.iso.ostypeid = self.getOsType("Other Linux (64-bit)")
+        self.md5 = "f7fee34a73a7f8e3adb30778c7c32c51"
+        self.sha256 = "069a22f7cc15b34cd39f6dd61ef0cf99ff47a1a92942772c30f50988746517f7"
+
+        if self.unsupportedHypervisor:
+            self.skipTest("Skipping test because unsupported hypervisor\
+                            %s" % self.hypervisor)
+        return
+
+    def tearDown(self):
+        try:
+            # Clean up the created templates
+            for temp in self.cleanup:
+                cmd = deleteIso.deleteIsoCmd()
+                cmd.id = temp.id
+                cmd.zoneid = self.zone.id
+                self.apiclient.deleteIso(cmd)
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_01_create_iso_with_checksum_sha1(self):
+        iso = self.registerIso(self.iso)
+        self.download(self.apiclient, iso.id)
+
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_02_create_iso_with_checksum_sha256(self):
+        self.iso.checksum = "{SHA-256}" + self.sha256
+        iso = self.registerIso(self.iso)
+        self.download(self.apiclient, iso.id)
+
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_03_create_iso_with_checksum_md5(self):
+        self.iso.checksum = "{md5}" + self.md5
+        iso = self.registerIso(self.iso)
+        self.download(self.apiclient, iso.id)
+
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_01_1_create_iso_with_checksum_sha1_negative(self):
+        self.iso.checksum = "{sha-1}" + "someInvalidValue"
+        iso = self.registerIso(self.iso)
+
+        try:
+            self.download(self.apiclient, iso.id)
+        except Exception as e:
+            print "Negative Test Passed - Exception Occurred Under iso download " \
+                  "%s" % GetDetailExceptionInfo(e)
+        else:
+            self.fail("Negative Test Failed - Exception DID NOT Occurred Under iso download ")
+
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_02_1_create_iso_with_checksum_sha256_negative(self):
+        self.iso.checksum = "{SHA-256}" + "someInvalidValue"
+        iso = self.registerIso(self.iso)
+
+        try:
+            self.download(self.apiclient, iso.id)
+        except Exception as e:
+            print "Negative Test Passed - Exception Occurred Under iso download " \
+                  "%s" % GetDetailExceptionInfo(e)
+        else:
+            self.fail("Negative Test Failed - Exception DID NOT Occurred Under iso download ")
+
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_03_1_create_iso_with_checksum_md5_negative(self):
+        self.iso.checksum = "{md5}" + "someInvalidValue"
+        iso = self.registerIso(self.iso)
+
+        try:
+            self.download(self.apiclient, iso.id)
+        except Exception as e:
+            print "Negative Test Passed - Exception Occurred Under iso download " \
+                  "%s" % GetDetailExceptionInfo(e)
+        else:
+            self.fail("Negative Test Failed - Exception DID NOT Occurred Under iso download ")
+
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_04_create_iso_with_no_checksum(self):
+        self.iso.checksum = None
+        iso = self.registerIso(self.iso)
+        self.download(self.apiclient, iso.id)
+
+    def registerIso(self, cmd):
+        iso = self.apiclient.registerIso(cmd)[0]
+        self.cleanup.append(iso)
+        return iso
+
+    def getOsType(self, param):
+        cmd = listOsTypes.listOsTypesCmd()
+        cmd.description = param
+        return self.apiclient.listOsTypes(cmd)[0].id
+
+    def download(self, apiclient, iso_id, retries=12, interval=5):
+        """Check if template download will finish in 1 minute"""
+        while retries > -1:
+            time.sleep(interval)
+            iso_response = Iso.list(
+                apiclient,
+                id=iso_id
+            )
+
+            if isinstance(iso_response, list):
+                iso = iso_response[0]
+                if not hasattr(iso, 'status') or not iso or not iso.status:
+                    retries = retries - 1
+                    continue
+
+                # If iso is ready,
+                # iso.status = Download Complete
+                # Downloading - x% Downloaded
+                # if Failed
+                # Error - Any other string
+                if 'Failed' in iso.status:
+                    raise Exception(
+                        "Failed to download iso: status - %s" %
+                        iso.status)
+
+                elif iso.status == 'Successfully Installed' and iso.isready:
+                    return
+
+                elif 'Downloaded' in iso.status:
+                    retries = retries - 1
+                    continue
+
+                elif 'Installing' not in iso.status:
+                    if retries >= 0:
+                        retries = retries - 1
+                        continue
+                    raise Exception(
+                        "Error in downloading iso: status - %s" %
+                        iso.status)
+
+            else:
+                retries = retries - 1
+        raise Exception("Template download failed exception.")
\ No newline at end of file
diff --git a/test/integration/smoke/test_templates.py b/test/integration/smoke/test_templates.py
index a621a0a..8d76de3 100644
--- a/test/integration/smoke/test_templates.py
+++ b/test/integration/smoke/test_templates.py
@@ -17,6 +17,8 @@
 """ BVT tests for Templates ISO
 """
 #Import Local Modules
+from marvin.cloudstackException import *
+from marvin.cloudstackAPI import *
 from marvin.codes import FAILED
 from marvin.cloudstackTestCase import cloudstackTestCase, unittest
 from marvin.cloudstackAPI import listZones
@@ -82,6 +84,203 @@ def create(apiclient, services, volumeid=None, account=None, domainid=None, proj
         cmd.projectid = projectid
     return apiclient.createTemplate(cmd)
 
+class TestCreateTemplateWithChecksum(cloudstackTestCase):
+    def setUp(self):
+        self.testClient = super(TestCreateTemplateWithChecksum, self).getClsTestClient()
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+
+        self.services = self.testClient.getParsedTestDataConfig()
+        self.unsupportedHypervisor = False
+        self.hypervisor = self.testClient.getHypervisorInfo()
+        if self.hypervisor.lower() in ['lxc']:
+            # Template creation from root volume is not supported in LXC
+            self.unsupportedHypervisor = True
+            return
+
+        # Get Zone, Domain and templates
+        self.domain = get_domain(self.apiclient)
+        self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests())
+
+        if "kvm" in self.hypervisor.lower():
+            self.test_template = registerTemplate.registerTemplateCmd()
+            self.test_template = registerTemplate.registerTemplateCmd()
+            self.test_template.checksum = "{SHA-1}" + "bf580a13f791d86acf3449a7b457a91a14389264"
+            self.test_template.hypervisor = self.hypervisor
+            self.test_template.zoneid = self.zone.id
+            self.test_template.name = 'test sha-2333'
+            self.test_template.displaytext = 'test sha-1'
+            self.test_template.url = "http://dl.openvm.eu/cloudstack/macchinina/x86_64/macchinina-kvm.qcow2.bz2"
+            self.test_template.format = "QCOW2"
+            self.test_template.ostypeid = self.getOsType("Other Linux (64-bit)")
+            self.md5 = "ada77653dcf1e59495a9e1ac670ad95f"
+            self.sha256 = "0efc03633f2b8f5db08acbcc5dc1be9028572dfd8f1c6c8ea663f0ef94b458c5"
+
+        if "vmware" in self.hypervisor.lower():
+            self.test_template = registerTemplate.registerTemplateCmd()
+            self.test_template = registerTemplate.registerTemplateCmd()
+            self.test_template.checksum = "{SHA-1}" + "b25d404de8335b4348ff01e49a95b403c90df466"
+            self.test_template.hypervisor = self.hypervisor
+            self.test_template.zoneid = self.zone.id
+            self.test_template.name = 'test sha-2333'
+            self.test_template.displaytext = 'test sha-1'
+            self.test_template.url = "http://dl.openvm.eu/cloudstack/macchinina/x86_64/macchinina-vmware.ova"
+            self.test_template.format = "OVA"
+            self.test_template.ostypeid = self.getOsType("Other Linux (64-bit)")
+            self.md5 = "d6d97389b129c7d898710195510bf4fb"
+            self.sha256 = "f57b59f118ab59284a70d6c63229d1de8f2d69bffc5a82b773d6c47e769c12d9"
+
+        if "xen" in self.hypervisor.lower():
+            self.test_template = registerTemplate.registerTemplateCmd()
+            self.test_template = registerTemplate.registerTemplateCmd()
+            self.test_template.checksum = "{SHA-1}" + "427fad501d0d8a1d63b8600a9a469fbf91191314"
+            self.test_template.hypervisor = self.hypervisor
+            self.test_template.zoneid = self.zone.id
+            self.test_template.name = 'test sha-2333'
+            self.test_template.displaytext = 'test sha-1'
+            self.test_template.url = "http://dl.openvm.eu/cloudstack/macchinina/x86_64/macchinina-xen.vhd.bz2"
+            self.test_template.format = "VHD"
+            self.test_template.ostypeid = self.getOsType("Other Linux (64-bit)")
+            self.md5 = "54ebc933e6e07ae58c0dc97dfd37c824"
+            self.sha256 = "bddd9876021d33df9792b71ae4b776598680ac68ecf55e9d9af33c80904cc1f3"
+
+        if self.unsupportedHypervisor:
+            self.skipTest("Skipping test because unsupported hypervisor\
+                            %s" % self.hypervisor)
+        return
+
+    def tearDown(self):
+        try:
+            # Clean up the created templates
+            for temp in self.cleanup:
+                cmd = deleteTemplate.deleteTemplateCmd()
+                cmd.id = temp.id
+                cmd.zoneid = self.zone.id
+                self.apiclient.deleteTemplate(cmd)
+
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_02_create_template_with_checksum_sha1(self):
+        template = self.registerTemplate(self.test_template)
+        self.download(self.apiclient, template.id)
+
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_03_create_template_with_checksum_sha256(self):
+        self.test_template.checksum = "{SHA-256}" + self.sha256
+        template = self.registerTemplate(self.test_template)
+        self.download(self.apiclient, template.id)
+
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_04_create_template_with_checksum_md5(self):
+        self.test_template.checksum = "{md5}" + self.md5
+        template = self.registerTemplate(self.test_template)
+        self.download(self.apiclient, template.id)
+
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_02_1_create_template_with_checksum_sha1_negative(self):
+        self.test_template.checksum = "{sha-1}" + "someInvalidValue"
+        template = self.registerTemplate(self.test_template)
+
+        try:
+            self.download(self.apiclient, template.id)
+        except Exception as e:
+            print "Negative Test Passed - Exception Occurred Under template download " \
+                  "%s" % GetDetailExceptionInfo(e)
+        else:
+            self.fail("Negative Test Failed - Exception DID NOT Occurred Under template download ")
+
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_03_1_create_template_with_checksum_sha256_negative(self):
+        self.test_template.checksum = "{SHA-256}" + "someInvalidValue"
+        template = self.registerTemplate(self.test_template)
+
+        try:
+            self.download(self.apiclient, template.id)
+        except Exception as e:
+            print "Negative Test Passed - Exception Occurred Under template download " \
+                  "%s" % GetDetailExceptionInfo(e)
+        else:
+            self.fail("Negative Test Failed - Exception DID NOT Occurred Under template download ")
+
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_04_1_create_template_with_checksum_md5_negative(self):
+        self.test_template.checksum = "{md5}" + "someInvalidValue"
+        template = self.registerTemplate(self.test_template)
+
+        try:
+            self.download(self.apiclient, template.id)
+        except Exception as e:
+            print "Negative Test Passed - Exception Occurred Under template download " \
+                  "%s" % GetDetailExceptionInfo(e)
+        else:
+            self.fail("Negative Test Failed - Exception DID NOT Occurred Under template download ")
+
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_05_create_template_with_no_checksum(self):
+        self.test_template.checksum = None
+        template = self.registerTemplate(self.test_template)
+        self.download(self.apiclient, template.id)
+
+    def registerTemplate(self, cmd):
+        temp = self.apiclient.registerTemplate(cmd)[0]
+        self.cleanup.append(temp)
+        return temp
+
+    def getOsType(self, param):
+        cmd = listOsTypes.listOsTypesCmd()
+        cmd.description = param
+        return self.apiclient.listOsTypes(cmd)[0].id
+
+    def download(self, apiclient, template_id, retries=12, interval=5):
+        """Check if template download will finish in 1 minute"""
+        while retries > -1:
+            time.sleep(interval)
+            template_response = Template.list(
+                apiclient,
+                id=template_id,
+                zoneid=self.zone.id,
+                templatefilter='self'
+            )
+
+            if isinstance(template_response, list):
+                template = template_response[0]
+                if not hasattr(template, 'status') or not template or not template.status:
+                    retries = retries - 1
+                    continue
+
+                # If template is ready,
+                # template.status = Download Complete
+                # Downloading - x% Downloaded
+                # if Failed
+                # Error - Any other string
+                if 'Failed' in template.status:
+                    raise Exception(
+                        "Failed to download template: status - %s" %
+                        template.status)
+
+                elif template.status == 'Download Complete' and template.isready:
+                    return
+
+                elif 'Downloaded' in template.status:
+                    retries = retries - 1
+                    continue
+
+                elif 'Installing' not in template.status:
+                    if retries >= 0:
+                        retries = retries - 1
+                        continue
+                    raise Exception(
+                        "Error in downloading template: status - %s" %
+                        template.status)
+
+            else:
+                retries = retries - 1
+        raise Exception("Template download failed exception.")
+
 
 class TestCreateTemplate(cloudstackTestCase):
 
diff --git a/utils/src/main/java/org/apache/cloudstack/utils/security/ChecksumValue.java b/utils/src/main/java/org/apache/cloudstack/utils/security/ChecksumValue.java
new file mode 100644
index 0000000..e47bf39
--- /dev/null
+++ b/utils/src/main/java/org/apache/cloudstack/utils/security/ChecksumValue.java
@@ -0,0 +1,86 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.utils.security;
+
+import java.util.Objects;
+
+import org.apache.commons.lang.StringUtils;
+
+public class ChecksumValue {
+    String checksum;
+    String algorithm = "MD5";
+    public ChecksumValue(String algorithm, String checksum) {
+        this.algorithm = algorithm;
+        this.checksum = checksum;
+    }
+    public ChecksumValue(String digest) {
+        digest = StringUtils.strip(digest);
+        this.algorithm = algorithmFromDigest(digest);
+        this.checksum = stripAlgorithmFromDigest(digest);
+    }
+
+    @Override
+    public String toString() {
+        return '{' + algorithm + '}'+ checksum;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        ChecksumValue that = (ChecksumValue)o;
+        return Objects.equals(getChecksum(), that.getChecksum()) && Objects.equals(getAlgorithm(), that.getAlgorithm());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getChecksum(), getAlgorithm());
+    }
+
+    public String getChecksum() {
+        return checksum;
+    }
+
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    private static String stripAlgorithmFromDigest(String digest) {
+        if(StringUtils.isNotEmpty(digest)) {
+            int s = digest.indexOf('{');// only assume a
+            int e = digest.indexOf('}');
+            if (s == 0 && e > s) { // we have an algorithm name of at least 1 char
+                return digest.substring(e+1);
+            }
+        }
+        // we assume digest is alright if there is no algorithm at the start
+        return digest;
+    }
+
+    private static String algorithmFromDigest(String digest) {
+        if(StringUtils.isNotEmpty(digest)) {
+            int s = digest.indexOf('{');
+            int e = digest.indexOf('}');
+            if (s == 0 && e > s+1) { // we have an algorithm name of at least 1 char
+                return digest.substring(s+1,e);
+            } // else if no algoritm
+        } // or if no digest at all
+        return "MD5";
+    }
+}
diff --git a/utils/src/main/java/org/apache/cloudstack/utils/security/DigestHelper.java b/utils/src/main/java/org/apache/cloudstack/utils/security/DigestHelper.java
new file mode 100644
index 0000000..67adf74
--- /dev/null
+++ b/utils/src/main/java/org/apache/cloudstack/utils/security/DigestHelper.java
@@ -0,0 +1,96 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.utils.security;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class DigestHelper {
+
+    public static ChecksumValue digest(String algorithm, InputStream is) throws NoSuchAlgorithmException, IOException {
+        MessageDigest digest = MessageDigest.getInstance(algorithm);
+        ChecksumValue checksum = null;
+        byte[] buffer = new byte[8192];
+        int read = 0;
+        while ((read = is.read(buffer)) > 0) {
+            digest.update(buffer, 0, read);
+        }
+        byte[] md5sum = digest.digest();
+        // TODO make sure this is valid for all types of checksums !?!
+        BigInteger bigInt = new BigInteger(1, md5sum);
+        checksum = new ChecksumValue(digest.getAlgorithm(), getPaddedDigestString(digest,bigInt));
+        return checksum;
+    }
+
+    public static boolean check(String checksum, InputStream is) throws IOException, NoSuchAlgorithmException {
+        ChecksumValue toCheckAgainst = new ChecksumValue(checksum);
+        String algorithm = toCheckAgainst.getAlgorithm();
+        ChecksumValue result = digest(algorithm,is);
+        return result.equals(toCheckAgainst);
+    }
+
+    public static String getPaddedDigest(String algorithm, String inputString) throws NoSuchAlgorithmException {
+        MessageDigest digest = MessageDigest.getInstance(algorithm);
+        String checksum;
+        digest.reset();
+        BigInteger pwInt = new BigInteger(1, digest.digest(inputString.getBytes()));
+        return getPaddedDigestString(digest, pwInt);
+    }
+
+    private static String getPaddedDigestString(MessageDigest digest, BigInteger pwInt) {
+        String checksum;
+        String pwStr = pwInt.toString(16);
+        // we have half byte string representation, so
+        int padding = 2*digest.getDigestLength() - pwStr.length();
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < padding; i++) {
+            sb.append('0'); // make sure the MD5 password is 32 digits long
+        }
+        sb.append(pwStr);
+        checksum = sb.toString();
+        return checksum;
+    }
+
+    static final Map<String, Integer> paddingLengths = creatPaddingLengths();
+
+    private static final Map<String, Integer> creatPaddingLengths() {
+        Map<String, Integer> map = new HashMap<>();
+        map.put("MD5", 32);
+        map.put("SHA-1", 40);
+        map.put("SHA-224", 56);
+        map.put("SHA-256", 64);
+        map.put("SHA-384", 96);
+        map.put("SHA-512", 128);
+        return map;
+    }
+
+    public static boolean isAlgorithmSupported(String checksum) {
+        ChecksumValue toCheckAgainst = new ChecksumValue(checksum);
+        String algorithm = toCheckAgainst.getAlgorithm();
+        try {
+            MessageDigest.getInstance(algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/utils/src/test/java/org/apache/cloudstack/utils/security/DigestHelperTest.java b/utils/src/test/java/org/apache/cloudstack/utils/security/DigestHelperTest.java
new file mode 100644
index 0000000..4540882
--- /dev/null
+++ b/utils/src/test/java/org/apache/cloudstack/utils/security/DigestHelperTest.java
@@ -0,0 +1,102 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.utils.security;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+
+import com.amazonaws.util.StringInputStream;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class DigestHelperTest {
+
+    private final static String INPUT_STRING = "01234567890123456789012345678901234567890123456789012345678901234567890123456789\n";
+    private final static String INPUT_STRING_NO2 = "01234567890123456789012345678901234567890123456789012345678901234567890123456789b\n";
+    private final static String INPUT_STRING_NO3 = "01234567890123456789012345678901234567890123456789012345678901234567890123456789h\n";
+    private final static String SHA256_CHECKSUM = "{SHA-256}c6ab15af7842d23d3c06c138b53a7d09c5e351a79c4eb3c8ca8d65e5ce8900ab";
+    private final static String SHA1_CHECKSUM = "{SHA-1}49e4b2f4292b63e88597c127d11bc2cc0f2ca0ff";
+    private final static String MD5_CHECKSUM = "{MD5}d141a8eeaf6bba779d1d1dc5102a81c5";
+    private final static String ZERO_PADDED_MD5_CHECKSUM = "{MD5}0e51dfa74b87f19dd5e0124d6a2195e3";
+    private final static String ZERO_PADDED_SHA256_CHECKSUM = "{SHA-256}08b5ae0c7d7d45d8ed406d7c3c7da695b81187903694314d97f8a37752a6b241";
+    private static final String MD5 = "MD5";
+    private static final String SHA_256 = "SHA-256";
+    private static InputStream inputStream;
+    private InputStream inputStream2;
+
+
+    @Test
+    public void check_SHA256() throws Exception {
+        Assert.assertTrue(DigestHelper.check(SHA256_CHECKSUM, inputStream));
+    }
+
+    @Test
+    public void check_SHA1() throws Exception {
+        Assert.assertTrue(DigestHelper.check(SHA1_CHECKSUM, inputStream));
+    }
+
+    @Test
+    public void check_MD5() throws Exception {
+        Assert.assertTrue(DigestHelper.check(MD5_CHECKSUM, inputStream));
+    }
+
+    @Test
+    public void testDigestSHA256() throws Exception {
+        String result = DigestHelper.digest(SHA_256, inputStream).toString();
+        Assert.assertEquals(SHA256_CHECKSUM, result);
+    }
+
+    @Test
+    public void testDigestSHA1() throws Exception {
+        String result = DigestHelper.digest("SHA-1", inputStream).toString();
+        Assert.assertEquals(SHA1_CHECKSUM, result);
+    }
+
+    @Test
+    public void testDigestMD5() throws Exception {
+        String result = DigestHelper.digest(MD5, inputStream).toString();
+        Assert.assertEquals(MD5_CHECKSUM, result);
+    }
+
+    @Test
+    public void testZeroPaddedDigestMD5() throws Exception {
+        inputStream2 = new StringInputStream(INPUT_STRING_NO2);
+        String result = DigestHelper.digest(MD5, inputStream2).toString();
+        Assert.assertEquals(ZERO_PADDED_MD5_CHECKSUM, result);
+    }
+
+    @Test
+    public void testZeroPaddedDigestSHA256() throws Exception {
+        inputStream2 = new StringInputStream(INPUT_STRING_NO3);
+        String result = DigestHelper.digest(SHA_256, inputStream2).toString();
+        Assert.assertEquals(ZERO_PADDED_SHA256_CHECKSUM, result);
+    }
+
+    @BeforeClass
+    public static void init() throws UnsupportedEncodingException {
+        inputStream = new StringInputStream(INPUT_STRING);
+    }
+    @Before
+    public void reset() throws IOException {
+        inputStream.reset();
+    }
+}
+
+//Generated with love by TestMe :) Please report issues and submit feature requests at: http://weirddev.com/forum#!/testme
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
['"commits@cloudstack.apache.org" <co...@cloudstack.apache.org>'].