Recientemente me fue solicitada ayuda para eloborar una función que encriptara una frase usando el algoritmo de
Cifrado de Playfair.
Crearemos una funcion llamada fnEncriptar que recibirá 2 parametros de tipo nvarchar: @entrada nvarchar(MAX) y @clave(25). Para este ejemplo usaré las misma frase (entrada) y clave usados en el artículo de wikipedia.
El primer paso es suprimir los espacios en blanco y opcionalmente pasamos la frase y clave a mayusculas.
SELECT @entrada = REPLACE(@entrada,' ','')
SET @entrada = UPPER(@entrada)
SELECT @clave = REPLACE(@clave,' ','')
SET @clave=UPPER(@clave)
Seguidamente generamos los poligramas aplicando las reglas y los almacenamos en una variable de tabla.
DECLARE @poligrama TABLE(Idp INT IDENTITY(1,1), par NVARCHAR(2) NOT NULL)
DECLARE @tam int,@pos INT
SET @tam=LEN(@entrada)
SET @pos=1
WHILE @pos<=@tam
BEGIN
IF (@pos+1)>@tam
INSERT INTO @poligrama(par)VALUES(SUBSTRING (@entrada,@pos,1)+'X')
ELSE
IF SUBSTRING (@entrada,@pos,1)=SUBSTRING (@entrada,@pos+1,1)
INSERT INTO @poligrama(par)VALUES(SUBSTRING (@entrada,@pos,1)+'X')
ELSE
INSERT INTO @poligrama(par)VALUES(SUBSTRING (@entrada,@pos,2))
SET @pos=@pos+2
END
A esta altura si hacemos un SELECT a la tabla poligramas tendremos el siguiente resultado:
Ahora procederemos aplicamos la regla a la contraseña eliminaremos los caracteres repetidos.
DECLARE @claveReducida NVARCHAR(25)
SET @tam=LEN(@clave)
SET @pos=1
SET @claveReducida=''
WHILE @pos<=@tam
BEGIN
IF CHARINDEX(SUBSTRING(@clave,@pos,1),@claveReducida)=0
SET @claveReducida=@claveReducida+SUBSTRING(@clave,@pos,1)
SET @pos = @pos +1
END
El siguiente paso es crear la matriz de encriptación (de intercambio) de caracteres.
| N | O | R | I | A |
| B | C | D | E | F |
| G | H | K | L | M |
| P | Q | S | T | U |
| V | W | X | Y | Z |
Los primeros elementos de la matriz deben ser los caracteres de la clave:
DECLARE @Matriz TABLE (FILA TINYINT, COLUMNA TINYINT, LETRA NVARCHAR(1))
DECLARE @fmz TINYINT, @cmz TINYINT
SET @pos = 1
SET @tam = LEN(@claveReducida)
SET @fmz=1
WHILE @fmz<=5 AND @pos<=@tam
BEGIN
SET @cmz=1
WHILE @cmz<=5 AND @pos<=@tam
BEGIN
INSERT INTO @Matriz(FILA, COLUMNA, LETRA)
VALUES(@fmz,@cmz,SUBSTRING(@claveReducida,@pos,1))
SET @pos = @pos + 1
SET @cmz= @cmz + 1
END
SET @fmz= @fmz + 1
END
Debe completarse la fila inconclusa con caracteres del alfabeto que no esten en la clave.
--GENERAR EL ALFABETO
DECLARE @iL tinyint, @MaxiL tinyint
--MAYUSCULAS
SET @iL = 65
SET @MaxiL = 90
--minusculas
--SET @iL = 97
--SET @MaxiL = 122
WHILE @cmz<=5
BEGIN
WHILE @iL <= @MaxiL AND @cmz<=5
BEGIN
IF CHAR(@iL) <> 'J' AND NOT EXISTS(SELECT * FROM @Matriz m WHERE m.LETRA = CHAR(@iL))
BEGIN
INSERT INTO @Matriz(FILA, COLUMNA, LETRA)
VALUES(@fmz,@cmz,CHAR(@iL))
--
SET @cmz= @cmz + 1
END
SET @iL = @iL + 1
END
END
Una vez hecho esto se completa la matriz al igual que el caso anterior excluyendo las J
WHILE @fmz<=5 AND (@iL<=@MaxiL)
BEGIN
SET @cmz=1
WHILE @cmz<=5 AND (@iL<=@MaxiL)
BEGIN
IF CHAR(@iL) <> 'J' AND NOT EXISTS(SELECT * FROM @Matriz m WHERE m.LETRA = CHAR(@iL))
BEGIN
INSERT INTO @Matriz(FILA, COLUMNA, LETRA)
VALUES(@fmz,@cmz,CHAR(@iL))
--
SET @cmz= @cmz + 1
END
--
SET @iL = @iL + 1
END
SET @fmz= @fmz + 1
END
Acá muestro parcialmente el resultado del segmento anterior
Ahora que se ha construido la matriz procedemos al intercambio de caracteres aplicando las reglas:
DECLARE @pgCount INT,@pgRow INT, @fila1 TINYINT, @fila2 TINYINT, @columna1 TINYINT, @columna2 TINYINT, @temp TINYINT
DECLARE @car1 NVARCHAR(1), @car2 NVARCHAR(1),@ncar1 NVARCHAR(1),@ncar2 NVARCHAR(1)
SELECT @pgCount = COUNT(*) FROM @poligrama p
SET @pgRow = 1
SET @SalidaEncriptada = ''
WHILE @pgRow <= @pgCount
BEGIN
--obtener los caracteres
SELECT @car1 = SUBSTRING(p.par,1,1),@car2=SUBSTRING(p.par,2,1) FROM @poligrama p
WHERE p.Idp = @pgRow
--sustituir j por i
if @car1 = 'J'
SET @car1 = 'I'
if @car2 = 'J'
SET @car2 = 'I'
--obtener la posicion de los caracteres en la matriz
SELECT @fila1=m.FILA, @columna1 = m.COLUMNA FROM @Matriz m WHERE m.LETRA = @car1;
SELECT @fila2=m.FILA, @columna2 = m.COLUMNA FROM @Matriz m WHERE m.LETRA = @car2;
--APLICAR REGLAS
IF @fila1=@fila2 --misma fila
BEGIN
IF @columna1<5
BEGIN
SET @columna1 = @columna1 +1
END
ELSE
BEGIN
SET @columna1 = 1
END
--
IF @columna2<5
BEGIN
SET @columna2 = @columna2 +1
END
ELSE
BEGIN
SET @columna2 = 1
END
END
ELSE
BEGIN
IF @columna1=@columna2 -- misma columna
BEGIN
IF @fila1<5
BEGIN
SET @fila1 = @fila1 +1
END
ELSE
BEGIN
SET @fila1 = 1
END
--
IF @fila2<5
BEGIN
SET @fila2 = @fila2 +1
END
ELSE
BEGIN
SET @fila2 = 1
END
END
ELSE
BEGIN
SET @temp = @columna1
SET @columna1 = @columna2
SET @columna2 = @temp
END
END
--Obtener caracter 1
SELECT @ncar1=m.LETRA FROM @Matriz m WHERE m.FILA = @fila1 AND m.COLUMNA = @columna1;
--Obtener caracter 2
SELECT @ncar2=m.LETRA FROM @Matriz m WHERE m.FILA = @fila2 AND m.COLUMNA = @columna2;
SET @SalidaEncriptada = @SalidaEncriptada + @ncar1 + @ncar2
SET @pgRow = @pgRow + 1
END
RETURN @SalidaEncriptada
Eso es todo amigos. Acá el resultado final.
Espero que les sea de utilidad. Agredezco sus comentarios constructivos.