Comment calculer hashbyte SHA1 en utilisant C #?

Dans un tableau, j'ai une URL colonne que j'utilise pour save les URL. Je calcule le hachage dans une autre colonne en utilisant la formule ( CONVERT([varbinary](20),hashbytes('SHA1',[URL])) ). Ça fonctionne bien.

Maintenant, j'ai besoin d'get une fonction similaire en C # pour get le hachage afin que je puisse comparer et vérifier que cette ligne similaire n'existe pas avant d'insert une nouvelle ligne. J'ai essayé quelques liens mais pas de chance.

Voici les liens:

http://weblogs.sqlteam.com/mladenp/archive/2009/04/28/Comparing-SQL-Server-HASHBYTES-function-and-.Net-hashing.aspx

Comment puis-je calculer l'équivalent de SQL Server (hashbytes ('SHA1', [ColumnName])) en C #?

 ** I found this link working. All I need to do is change formula in the db. but is it possible to make it in one line ** 

http://forums.asp.net/t/1782626.aspx

 DECLARE @HashThis nvarchar(4000); DECLARE @BinHash varbinary(4000); SELECT @HashThis = CONVERT(nvarchar(4000),'Password@Test'); SELECT @BinHash = HashBytes('SHA1', @HashThis); SELECT cast(N'' as xml).value('xs:base64Binary(xs:hexBinary(sql:variable("@BinHash")))', 'nvarchar(4000)'); 

en c #

 ssortingng pwd = "Password@Test"; var sha1Provider = HashAlgorithm.Create("SHA1"); var binHash = sha1Provider.ComputeHash(Encoding.Unicode.GetBytes(pwd)); Console.WriteLine(Convert.ToBase64Ssortingng(binHash)); 

J'utilise SQL Server 2012. Collation pour la database est SQL_Latin1_General_CP1_CI_AS

Merci

Paraminder

C'est un problème d'enencoding:

C # /. Les strings Net / CLR sont, en interne, des strings codées en UTF-16. Cela signifie que chaque personnage a au less deux octets.

SQL Server est différent:

  • char et varchar représentent chaque caractère sous la forme d'un octet unique en utilisant la page de code liée au collation utilisé par cette colonne

  • nchar et nvarchar représentent chaque caractère comme 2 octets en utilisant le encoding UCS-2 [ancien et obsolète] pour Unicode – quelque chose qui a été déprécié en 1996 avec la sortie de Unicode 2.0 et UTF-16.

    La grande différence entre UTF-16 et UCS-2 est que UCS-2 ne peut représenter que des caractères dans le BMP Unicode (Basic Multilingual Plane); UTF-16 peut représenter n'importe quel caractère Unicode. Si je comprends bien, dans le BMP, les représentations UCS-2 et UTF-16 sont identiques.

Cela signifie que pour calculer un hachage identique à celui calculé par SQL Server, vous devez get une représentation en octets identique à celle de SQL Server. Comme il semble que vous utilisiez char ou varchar avec la collation SQL_Latin1_General_CP1_CI_AS , d'après la documentation , la partie CP1 signifie la page de codes 1252 et le rest signifie insensible à la casse, sensible à l'accent. Alors…

Vous pouvez get l'enencoding pour la page de codes 1252 en:

 Encoding enc = Encoding.GetEncoding(1252); 

En utilisant cette information, et étant donné ce tableau:

 create table dbo.hash_test ( id int not null identity(1,1) primary key clustered , source_text varchar(2000) collate SQL_Latin1_General_CP1_CI_AS not null , hash as ( hashbytes( 'SHA1' , source_text ) ) , ) go insert dbo.hash_test ( source_text ) values ( 'the quick brown fox jumped over the lazy dog.' ) insert dbo.hash_test ( source_text ) values ( 'She looked like something that might have occured to Ibsen in one of his less frivolous moments.' ) go 

Vous obtiendrez cette sortie

 1: the quick brown fox jumped over the lazy dog. sql: 6039D100 3323D483 47DDFDB5 CE2842DF 758FAB5F c#: 6039D100 3323D483 47DDFDB5 CE2842DF 758FAB5F 2: She looked like something that might have occured to Ibsen in one of his less frivolous moments. sql: D92501ED C462E331 B0E129BF 5B4A854E 8DBC490C c#: D92501ED C462E331 B0E129BF 5B4A854E 8DBC490C 

de ce programme

 class Program { static byte[] Sha1Hash( ssortingng s ) { SHA1 sha1 = SHA1.Create() ; Encoding windows1252 = Encoding.GetEncoding(1252) ; byte[] octets = windows1252.GetBytes(s) ; byte[] hash = sha1.ComputeHash( octets ) ; return hash ; } static ssortingng HashToSsortingng( byte[] bytes ) { SsortingngBuilder sb = new SsortingngBuilder() ; for ( int i = 0 ; i < bytes.Length ; ++i ) { byte b = bytes[i] ; if ( i > 0 && 0 == i % 4 ) sb.Append( ' ' ) ; sb.AppendFormat( b.ToSsortingng("X2") ) ; } ssortingng s = sb.ToSsortingng() ; return s ; } private static DataTable ReadDataFromSqlServer() { DataTable dt = new DataTable(); using ( SqlConnection conn = new SqlConnection( "Server=localhost;Database=sandbox;Trusted_Connection=True;")) using ( SqlCommand cmd = conn.CreateCommand() ) using ( SqlDataAdapter sda = new SqlDataAdapter(cmd) ) { cmd.CommandText = "select * from dbo.hash_test" ; cmd.CommandType = CommandType.Text; conn.Open(); sda.Fill( dt ) ; conn.Close() ; } return dt ; } static void Main() { DataTable dt = ReadDataFromSqlServer() ; foreach ( DataRow row in dt.Rows ) { int id = (int) row[ "id" ] ; ssortingng sourceText = (ssortingng) row[ "source_text" ] ; byte[] sqlServerHash = (byte[]) row[ "hash" ] ; byte[] myHash = Sha1Hash( sourceText ) ; Console.WriteLine(); Console.WriteLine( "{0:##0}: {1}" , id , sourceText ) ; Console.WriteLine( " sql: {0}" , HashToSsortingng( sqlServerHash ) ) ; Console.WriteLine( " c#: {0}" , HashToSsortingng( myHash ) ) ; Debug.Assert( sqlServerHash.SequenceEqual(myHash) ) ; } return ; } } 

Facile!

Je suggérerais que chaque fois qu'un hash est créé, il soit fait en un seul endroit. Soit dans le code ou sur la database. Cela vous facilitera la vie à long terme. Cela signifierait soit de changer votre code C # pour créer le hachage avant d'insert l'logging ou de faire la vérification de la duplication dans une procédure stockée à la place.

Quoi qu'il en soit, la vérification et l'insertion de duplication doivent être synchronisées de sorte qu'aucune autre insertion ne puisse avoir lieu entre le moment où vous vérifiez les duplicates et celui où l'logging est réellement inséré. Le moyen le plus simple de le faire serait de les exécuter tous les deux dans la même transaction.

Si vous insistez pour laisser la logique en l'état, je vous suggère de créer le hachage dans la database, mais de l'exposer via une procédure stockée ou une fonction définie par l'user qui pourrait être appelée à partir de votre code C #.