@@ -534,3 +534,287 @@ TEST(basic, aead_info) {
534534 ASSERT_EQ (aead.getMaxTagLength (), 16 );
535535}
536536#endif
537+
538+ // ============================================================================
539+ // Argon2 KDF tests (OpenSSL 3.2.0+ only)
540+
541+ #if OPENSSL_VERSION_NUMBER >= 0x30200000L
542+ #ifndef OPENSSL_NO_ARGON2
543+
544+ TEST (KDF, argon2i) {
545+ const char * password = " password" ;
546+ const unsigned char salt[] = {0x01 ,
547+ 0x02 ,
548+ 0x03 ,
549+ 0x04 ,
550+ 0x05 ,
551+ 0x06 ,
552+ 0x07 ,
553+ 0x08 ,
554+ 0x09 ,
555+ 0x0a ,
556+ 0x0b ,
557+ 0x0c ,
558+ 0x0d ,
559+ 0x0e ,
560+ 0x0f ,
561+ 0x10 };
562+ const size_t length = 32 ;
563+
564+ Buffer<const char > passBuf{password, strlen (password)};
565+ Buffer<const unsigned char > saltBuf{salt, sizeof (salt)};
566+ Buffer<const unsigned char > secret{nullptr , 0 };
567+ Buffer<const unsigned char > ad{nullptr , 0 };
568+
569+ // Use small parameters for testing
570+ // lanes=1, memcost=16 (KB), iter=3, version=0x13 (1.3)
571+ auto result = argon2 (passBuf,
572+ saltBuf,
573+ 1 ,
574+ length,
575+ 16 ,
576+ 3 ,
577+ 0x13 ,
578+ secret,
579+ ad,
580+ Argon2Type::ARGON2I);
581+ ASSERT_TRUE (result);
582+ ASSERT_EQ (result.size (), length);
583+
584+ // Verify output is not all zeros
585+ bool allZeros = true ;
586+ for (size_t i = 0 ; i < length; i++) {
587+ if (reinterpret_cast <unsigned char *>(result.get ())[i] != 0 ) {
588+ allZeros = false ;
589+ break ;
590+ }
591+ }
592+ ASSERT_FALSE (allZeros);
593+ }
594+
595+ TEST (KDF, argon2d) {
596+ const char * password = " password" ;
597+ const unsigned char salt[] = {0x01 ,
598+ 0x02 ,
599+ 0x03 ,
600+ 0x04 ,
601+ 0x05 ,
602+ 0x06 ,
603+ 0x07 ,
604+ 0x08 ,
605+ 0x09 ,
606+ 0x0a ,
607+ 0x0b ,
608+ 0x0c ,
609+ 0x0d ,
610+ 0x0e ,
611+ 0x0f ,
612+ 0x10 };
613+ const size_t length = 32 ;
614+
615+ Buffer<const char > passBuf{password, strlen (password)};
616+ Buffer<const unsigned char > saltBuf{salt, sizeof (salt)};
617+ Buffer<const unsigned char > secret{nullptr , 0 };
618+ Buffer<const unsigned char > ad{nullptr , 0 };
619+
620+ auto result = argon2 (passBuf,
621+ saltBuf,
622+ 1 ,
623+ length,
624+ 16 ,
625+ 3 ,
626+ 0x13 ,
627+ secret,
628+ ad,
629+ Argon2Type::ARGON2D);
630+ ASSERT_TRUE (result);
631+ ASSERT_EQ (result.size (), length);
632+ }
633+
634+ TEST (KDF, argon2id) {
635+ const char * password = " password" ;
636+ const unsigned char salt[] = {0x01 ,
637+ 0x02 ,
638+ 0x03 ,
639+ 0x04 ,
640+ 0x05 ,
641+ 0x06 ,
642+ 0x07 ,
643+ 0x08 ,
644+ 0x09 ,
645+ 0x0a ,
646+ 0x0b ,
647+ 0x0c ,
648+ 0x0d ,
649+ 0x0e ,
650+ 0x0f ,
651+ 0x10 };
652+ const size_t length = 32 ;
653+
654+ Buffer<const char > passBuf{password, strlen (password)};
655+ Buffer<const unsigned char > saltBuf{salt, sizeof (salt)};
656+ Buffer<const unsigned char > secret{nullptr , 0 };
657+ Buffer<const unsigned char > ad{nullptr , 0 };
658+
659+ auto result = argon2 (passBuf,
660+ saltBuf,
661+ 1 ,
662+ length,
663+ 16 ,
664+ 3 ,
665+ 0x13 ,
666+ secret,
667+ ad,
668+ Argon2Type::ARGON2ID);
669+ ASSERT_TRUE (result);
670+ ASSERT_EQ (result.size (), length);
671+ }
672+
673+ TEST (KDF, argon2_with_secret_and_ad) {
674+ const char * password = " password" ;
675+ const unsigned char salt[] = {0x01 ,
676+ 0x02 ,
677+ 0x03 ,
678+ 0x04 ,
679+ 0x05 ,
680+ 0x06 ,
681+ 0x07 ,
682+ 0x08 ,
683+ 0x09 ,
684+ 0x0a ,
685+ 0x0b ,
686+ 0x0c ,
687+ 0x0d ,
688+ 0x0e ,
689+ 0x0f ,
690+ 0x10 };
691+ const unsigned char secretData[] = {0xaa , 0xbb , 0xcc , 0xdd };
692+ const unsigned char adData[] = {0x11 , 0x22 , 0x33 , 0x44 , 0x55 };
693+ const size_t length = 32 ;
694+
695+ Buffer<const char > passBuf{password, strlen (password)};
696+ Buffer<const unsigned char > saltBuf{salt, sizeof (salt)};
697+ Buffer<const unsigned char > secret{secretData, sizeof (secretData)};
698+ Buffer<const unsigned char > ad{adData, sizeof (adData)};
699+
700+ auto result = argon2 (passBuf,
701+ saltBuf,
702+ 1 ,
703+ length,
704+ 16 ,
705+ 3 ,
706+ 0x13 ,
707+ secret,
708+ ad,
709+ Argon2Type::ARGON2ID);
710+ ASSERT_TRUE (result);
711+ ASSERT_EQ (result.size (), length);
712+ }
713+
714+ TEST (KDF, argon2_empty_password) {
715+ const unsigned char salt[] = {0x01 ,
716+ 0x02 ,
717+ 0x03 ,
718+ 0x04 ,
719+ 0x05 ,
720+ 0x06 ,
721+ 0x07 ,
722+ 0x08 ,
723+ 0x09 ,
724+ 0x0a ,
725+ 0x0b ,
726+ 0x0c ,
727+ 0x0d ,
728+ 0x0e ,
729+ 0x0f ,
730+ 0x10 };
731+ const size_t length = 32 ;
732+
733+ Buffer<const char > passBuf{" " , 0 };
734+ Buffer<const unsigned char > saltBuf{salt, sizeof (salt)};
735+ Buffer<const unsigned char > secret{nullptr , 0 };
736+ Buffer<const unsigned char > ad{nullptr , 0 };
737+
738+ // Empty password should still work
739+ auto result = argon2 (passBuf,
740+ saltBuf,
741+ 1 ,
742+ length,
743+ 16 ,
744+ 3 ,
745+ 0x13 ,
746+ secret,
747+ ad,
748+ Argon2Type::ARGON2ID);
749+ ASSERT_TRUE (result);
750+ ASSERT_EQ (result.size (), length);
751+ }
752+
753+ TEST (KDF, argon2_different_types_produce_different_output) {
754+ const char * password = " password" ;
755+ const unsigned char salt[] = {0x01 ,
756+ 0x02 ,
757+ 0x03 ,
758+ 0x04 ,
759+ 0x05 ,
760+ 0x06 ,
761+ 0x07 ,
762+ 0x08 ,
763+ 0x09 ,
764+ 0x0a ,
765+ 0x0b ,
766+ 0x0c ,
767+ 0x0d ,
768+ 0x0e ,
769+ 0x0f ,
770+ 0x10 };
771+ const size_t length = 32 ;
772+
773+ Buffer<const char > passBuf{password, strlen (password)};
774+ Buffer<const unsigned char > saltBuf{salt, sizeof (salt)};
775+ Buffer<const unsigned char > secret{nullptr , 0 };
776+ Buffer<const unsigned char > ad{nullptr , 0 };
777+
778+ auto resultI = argon2 (passBuf,
779+ saltBuf,
780+ 1 ,
781+ length,
782+ 16 ,
783+ 3 ,
784+ 0x13 ,
785+ secret,
786+ ad,
787+ Argon2Type::ARGON2I);
788+ auto resultD = argon2 (passBuf,
789+ saltBuf,
790+ 1 ,
791+ length,
792+ 16 ,
793+ 3 ,
794+ 0x13 ,
795+ secret,
796+ ad,
797+ Argon2Type::ARGON2D);
798+ auto resultID = argon2 (passBuf,
799+ saltBuf,
800+ 1 ,
801+ length,
802+ 16 ,
803+ 3 ,
804+ 0x13 ,
805+ secret,
806+ ad,
807+ Argon2Type::ARGON2ID);
808+
809+ ASSERT_TRUE (resultI);
810+ ASSERT_TRUE (resultD);
811+ ASSERT_TRUE (resultID);
812+
813+ // All three types should produce different outputs
814+ ASSERT_NE (memcmp (resultI.get (), resultD.get (), length), 0 );
815+ ASSERT_NE (memcmp (resultI.get (), resultID.get (), length), 0 );
816+ ASSERT_NE (memcmp (resultD.get (), resultID.get (), length), 0 );
817+ }
818+
819+ #endif // OPENSSL_NO_ARGON2
820+ #endif // OPENSSL_VERSION_NUMBER >= 0x30200000L
0 commit comments